QuLab 2.4.20__cp311-cp311-win_amd64.whl → 2.5.0__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.4.20
3
+ Version: 2.5.0
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,17 +1,18 @@
1
- qulab/__init__.py,sha256=vkFybY8YSsQilYdThPRD83-btPAR41sy_WCXiM-6mME,141
2
- qulab/__main__.py,sha256=g9iBs8xxX6Yik7cmgllQkpBN8C4JNoZVsEOyCCLCyFU,63
1
+ qulab/__init__.py,sha256=pdlicy07Dx39pTEGZ0i41Ox9tuuuKKIdsFIrE13bneg,249
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=R96iJRfL-QZSf9reOnccgip5md-3EdMl21n0JSZs4lY,31744
5
- qulab/version.py,sha256=0EYwz_vOIrGy7c3cr82zYeYGyK4QxRsY1XkcDC_j6SI,22
6
- qulab/cli/__init__.py,sha256=6xd2eYw32k1NmfAuYSu__1kaP12Oz1QVqwbkYXdWno4,588
7
- qulab/cli/config.py,sha256=Loee8MwKFuDRWXttG8iBY9ZmD5xSCHDFi3ztt2i0S_0,3139
4
+ qulab/fun.cp311-win_amd64.pyd,sha256=Ou3oaF6r91_RUTvb-1Qc5yorMZQpcgdsW36pPtNCiN8,31744
5
+ qulab/version.py,sha256=b9PgnIDmp0TYLJmDYb-w9iqcfWXZk22bBNQQjBVgaf0,21
6
+ qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ qulab/cli/commands.py,sha256=6xd2eYw32k1NmfAuYSu__1kaP12Oz1QVqwbkYXdWno4,588
8
+ qulab/cli/config.py,sha256=tNmH4ggdgrFqcQa2WZKLpidiYTg95_UnT0paDJ4fi4c,3204
8
9
  qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
9
10
  qulab/executor/cli.py,sha256=owdDSaSuzTPQA5SlNCxX4nHWITU1BF0VZMj7tLqCZhM,5781
10
- qulab/executor/load.py,sha256=fZNmsOGR_2s1IykVmVwziDKeWCIej-jRJAQzKJRUdaE,11990
11
- qulab/executor/schedule.py,sha256=bXQzn3e3tCvAVdEBsvh5ecAThP52njyxbsrlrxC9TzA,11922
12
- qulab/executor/storage.py,sha256=M66Q5_Uc5MMfc_QAuuaaexwAz7wxBPMkeleB5nRpQmI,4621
11
+ qulab/executor/load.py,sha256=4QJI_jWUCrn0MW_ieTAyhUXmujrOU5D9ywSOqzNduu0,11992
12
+ qulab/executor/schedule.py,sha256=u-eM9Cw8GrvWmRFhHQWSXcdKomxp6AqSwnSm3gDwkrM,11920
13
+ qulab/executor/storage.py,sha256=V91y8z62GseJLm2-1k-empbw68pCq93Lk-nUAwtfVfs,6068
13
14
  qulab/executor/transform.py,sha256=inaOn6eqCs22ZZ0xAQl8s8YCoEACaXSwFNNu7jqdwAk,2148
14
- qulab/executor/utils.py,sha256=_9EZkx2rBpsWjhDN5BZ-Lq9MboqmHcI1jtwpRyrzSTY,3101
15
+ qulab/executor/utils.py,sha256=OVBYuAC4Pw8-kT_s0AJUiLAS5QTeV-mXF8zjdQFTwrM,3163
15
16
  qulab/monitor/__init__.py,sha256=xEVDkJF8issrsDeLqQmDsvtRmrf-UiViFcGTWuzdlFU,43
16
17
  qulab/monitor/__main__.py,sha256=k2H1H5Zf9LLXTDLISJkbikLH-z0f1e5i5i6wXXYPOrE,105
17
18
  qulab/monitor/config.py,sha256=y_5StMkdrbZO1ziyKBrvIkB7Jclp9RCPK1QbsOhCxnY,785
@@ -91,9 +92,9 @@ qulab/visualization/plot_seq.py,sha256=Uo1-dB1YE9IN_A9tuaOs9ZG3S5dKDQ_l98iD2Wbxp
91
92
  qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
92
93
  qulab/visualization/rot3d.py,sha256=jGHJcqj1lEWBUV-W4GUGONGacqjrYvuFoFCwPse5h1Y,757
93
94
  qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
94
- QuLab-2.4.20.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
95
- QuLab-2.4.20.dist-info/METADATA,sha256=LzlzxYnUG7CckjTxnZ2-2yJY7yfwUFlf5pll5JI_PV4,3804
96
- QuLab-2.4.20.dist-info/WHEEL,sha256=yNnHoQL2GZYIUXm9YvoaBpFjGlUoK9qq9oqYeudrWlE,101
97
- QuLab-2.4.20.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
98
- QuLab-2.4.20.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
99
- QuLab-2.4.20.dist-info/RECORD,,
95
+ QuLab-2.5.0.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
96
+ QuLab-2.5.0.dist-info/METADATA,sha256=dUio4DApvpQRgt7j7w3aYyCqfxDqpbsnTmFuMQirwXw,3803
97
+ QuLab-2.5.0.dist-info/WHEEL,sha256=yNnHoQL2GZYIUXm9YvoaBpFjGlUoK9qq9oqYeudrWlE,101
98
+ QuLab-2.5.0.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
99
+ QuLab-2.5.0.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
100
+ QuLab-2.5.0.dist-info/RECORD,,
qulab/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
+ from .executor.storage import find_result
2
+ from .executor.storage import get_result_by_index as get_result
1
3
  from .scan import Scan, get_record, load_record, lookup, lookup_list
2
4
  from .version import __version__
3
5
  from .visualization import autoplot
qulab/__main__.py CHANGED
@@ -1,4 +1,4 @@
1
- from .cli import cli
1
+ from .cli.commands import cli
2
2
 
3
3
  if __name__ == '__main__':
4
4
  cli()
qulab/cli/__init__.py CHANGED
@@ -1,29 +0,0 @@
1
- import click
2
-
3
- from ..executor.cli import create, get, maintain, run, set
4
- from ..monitor.__main__ import main as monitor
5
- from ..scan.server import server
6
- from ..sys.net.cli import dht
7
- from ..visualization.__main__ import plot
8
-
9
-
10
- @click.group()
11
- def cli():
12
- pass
13
-
14
-
15
- @cli.command()
16
- def hello():
17
- """Print hello world."""
18
- click.echo('hello, world')
19
-
20
-
21
- cli.add_command(monitor)
22
- cli.add_command(plot)
23
- cli.add_command(dht)
24
- cli.add_command(server)
25
- cli.add_command(maintain)
26
- cli.add_command(run)
27
- cli.add_command(create)
28
- cli.add_command(set)
29
- cli.add_command(get)
qulab/cli/commands.py ADDED
@@ -0,0 +1,29 @@
1
+ import click
2
+
3
+ from ..executor.cli import create, get, maintain, run, set
4
+ from ..monitor.__main__ import main as monitor
5
+ from ..scan.server import server
6
+ from ..sys.net.cli import dht
7
+ from ..visualization.__main__ import plot
8
+
9
+
10
+ @click.group()
11
+ def cli():
12
+ pass
13
+
14
+
15
+ @cli.command()
16
+ def hello():
17
+ """Print hello world."""
18
+ click.echo('hello, world')
19
+
20
+
21
+ cli.add_command(monitor)
22
+ cli.add_command(plot)
23
+ cli.add_command(dht)
24
+ cli.add_command(server)
25
+ cli.add_command(maintain)
26
+ cli.add_command(run)
27
+ cli.add_command(create)
28
+ cli.add_command(set)
29
+ cli.add_command(get)
qulab/cli/config.py CHANGED
@@ -62,27 +62,35 @@ def log_options(func):
62
62
 
63
63
  @click.option("--debug",
64
64
  is_flag=True,
65
- default=lambda: get_config_value("debug", bool) or False,
65
+ default=get_config_value("debug", bool),
66
66
  help=f"Enable debug mode")
67
67
  @click.option("--log",
68
68
  type=click.Path(),
69
69
  default=lambda: get_config_value("log", Path),
70
70
  help=f"Log file path")
71
+ @click.option("--quiet",
72
+ is_flag=True,
73
+ default=get_config_value("quiet", bool),
74
+ help=f"Disable log output")
71
75
  @functools.wraps(func)
72
- def wrapper(*args, log=None, debug=False, **kwargs):
73
- if log is None and not debug:
74
- logger.remove()
75
- logger.add(sys.stderr, level='INFO')
76
- elif log is None and debug:
77
- logger.remove()
78
- logger.add(sys.stderr, level='DEBUG')
79
- elif log is not None and not debug:
80
- logger.configure(handlers=[dict(sink=log, level='INFO')])
81
- elif log is not None and debug:
82
- logger.configure(handlers=[
83
- dict(sink=log, level='DEBUG'),
84
- dict(sink=sys.stderr, level='DEBUG')
85
- ])
76
+ def wrapper(*args, **kwargs):
77
+ debug = bool(kwargs.pop("debug"))
78
+ log = kwargs.pop("log")
79
+ quiet = bool(kwargs.pop("quiet"))
80
+
81
+ if debug:
82
+ log_level = "DEBUG"
83
+ else:
84
+ log_level = "INFO"
85
+
86
+ handlers = []
87
+ if log is not None:
88
+ handlers.append(dict(sink=log, level=log_level))
89
+ if not quiet or debug:
90
+ handlers.append(dict(sink=sys.stderr, level=log_level))
91
+
92
+ logger.configure(handlers=handlers)
93
+
86
94
  return func(*args, **kwargs)
87
95
 
88
96
  return wrapper
qulab/executor/load.py CHANGED
@@ -269,7 +269,7 @@ def load_workflow_from_template(template_path: str,
269
269
  str: 已经替换的新字符串。
270
270
  """
271
271
  pattern = re.compile(r'VAR\s*\(\s*(["\'])(\w+)\1\s*\)')
272
- replacement = f'__VAR_{hash_str}' + r'["\2"]'
272
+ replacement = f'__VAR_{hash_str}' + r'[\1\2\1]'
273
273
  new_text = re.sub(pattern, replacement, text)
274
274
  return new_text
275
275
 
@@ -7,8 +7,8 @@ from loguru import logger
7
7
 
8
8
  from . import transform
9
9
  from .load import WorkflowType, get_dependents
10
- from .storage import (Result, find_result, get_head, renew_result,
11
- revoke_result, save_result)
10
+ from .storage import (Result, find_result, renew_result, revoke_result,
11
+ save_result)
12
12
 
13
13
 
14
14
  class CalibrationFailedError(Exception):
@@ -120,13 +120,14 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
120
120
 
121
121
  if hasattr(workflow, 'check') and callable(workflow.check) and hasattr(
122
122
  workflow, 'check_analyze') and callable(workflow.check_analyze):
123
- logger.debug(f'Checking "{workflow}" with "check" method ...')
123
+ logger.debug(
124
+ f'Checking "{workflow.__workflow_id__}" with "check" method ...')
124
125
  data = workflow.check()
125
126
  result = Result()
126
127
  result.data = data
127
- save_result(workflow.__workflow_id__, result, state_path)
128
+ #save_result(workflow.__workflow_id__, result, state_path)
128
129
 
129
- logger.debug(f'Checked "{workflow}" !')
130
+ logger.debug(f'Checked "{workflow.__workflow_id__}" !')
130
131
  result = call_analyzer(workflow, data, history, check=True, plot=plot)
131
132
  if result.in_spec:
132
133
  logger.debug(
@@ -149,8 +150,10 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
149
150
 
150
151
  logger.debug(f'Calibrated "{workflow}" !')
151
152
  result = call_analyzer(workflow, data, history, check=False, plot=plot)
152
- save_result(workflow.__workflow_id__, result, state_path,
153
- get_head(workflow.__workflow_id__, state_path))
153
+ save_result(workflow.__workflow_id__,
154
+ result,
155
+ state_path,
156
+ overwrite=True)
154
157
 
155
158
  return result
156
159
 
@@ -167,8 +170,7 @@ def calibrate(workflow: WorkflowType, code_path: str | Path,
167
170
  save_result(workflow.__workflow_id__, result, state_path)
168
171
  logger.debug(f'Calibrated "{workflow.__workflow_id__}" !')
169
172
  result = call_analyzer(workflow, data, history, check=False, plot=plot)
170
- save_result(workflow.__workflow_id__, result, state_path,
171
- get_head(workflow.__workflow_id__, state_path))
173
+ save_result(workflow.__workflow_id__, result, state_path, overwrite=True)
172
174
  return result
173
175
 
174
176
 
qulab/executor/storage.py CHANGED
@@ -1,3 +1,4 @@
1
+ import lzma
1
2
  import pickle
2
3
  import uuid
3
4
  from dataclasses import dataclass, field
@@ -6,6 +7,8 @@ from pathlib import Path
6
7
 
7
8
  from loguru import logger
8
9
 
10
+ from ..cli.config import get_config_value
11
+
9
12
 
10
13
  @dataclass
11
14
  class Result():
@@ -18,25 +21,16 @@ class Result():
18
21
  params: dict = field(default_factory=dict)
19
22
  info: dict = field(default_factory=dict)
20
23
  data: tuple = field(default_factory=tuple)
21
- previous: Path | None = None
22
-
23
-
24
- class Graph:
25
-
26
- def __init__(self):
27
- self.nodes = {}
28
- self.heads = set()
29
- self.roots = set()
24
+ index: int = -1
25
+ previous_path: Path | None = None
26
+ base_path: Path | None = None
30
27
 
31
- def add_node(self, node: str, deps: list[str]):
32
- if node not in self.nodes:
33
- self.nodes[node] = deps
34
- if not deps:
35
- self.heads.add(node)
36
- for dep in deps:
37
- if dep not in self.nodes:
38
- self.nodes[dep] = []
39
- self.roots.discard(dep)
28
+ @property
29
+ def previous(self):
30
+ if self.previous_path is not None and self.base_path is not None:
31
+ return load_result(self.previous_path, self.base_path)
32
+ else:
33
+ return None
40
34
 
41
35
 
42
36
  def random_path(base: Path) -> Path:
@@ -50,27 +44,54 @@ def random_path(base: Path) -> Path:
50
44
  def save_result(workflow: str,
51
45
  result: Result,
52
46
  base_path: str | Path,
53
- path: Path | None = None):
47
+ overwrite: bool = False):
54
48
  logger.debug(
55
49
  f'Saving result for "{workflow}", {result.in_spec=}, {result.bad_data=}, {result.fully_calibrated=}'
56
50
  )
57
51
  base_path = Path(base_path)
58
- if path is None:
59
- path = random_path(base_path)
60
- (base_path / 'objects' / path).parent.mkdir(parents=True, exist_ok=True)
61
- result.previous = get_head(workflow, base_path)
52
+ if overwrite:
53
+ buf = lzma.compress(pickle.dumps(result))
54
+ path = get_head(workflow, base_path)
55
+ with open(base_path / 'objects' / path, "rb") as f:
56
+ index = int.from_bytes(f.read(8), 'big')
57
+ result.index = index
58
+ else:
59
+ result.previous_path = get_head(workflow, base_path)
60
+ buf = lzma.compress(pickle.dumps(result))
61
+ path = random_path(base_path / 'objects')
62
+ (base_path / 'objects' / path).parent.mkdir(parents=True,
63
+ exist_ok=True)
64
+ result.index = create_index("result",
65
+ base_path,
66
+ context=str(path),
67
+ width=35)
68
+
62
69
  with open(base_path / 'objects' / path, "wb") as f:
63
- pickle.dump(result, f)
70
+ f.write(result.index.to_bytes(8, 'big'))
71
+ f.write(buf)
64
72
  set_head(workflow, path, base_path)
65
73
 
66
74
 
67
- def find_result(workflow: str, base_path: str | Path) -> Result | None:
75
+ def load_result(path: str | Path, base_path: str | Path) -> Result | None:
76
+ base_path = Path(base_path)
77
+ path = base_path / 'objects' / path
78
+
79
+ with open(base_path / 'objects' / path, "rb") as f:
80
+ index = int.from_bytes(f.read(8), 'big')
81
+ result = pickle.loads(lzma.decompress(f.read()))
82
+ result.base_path = base_path
83
+ result.index = index
84
+ return result
85
+
86
+
87
+ def find_result(
88
+ workflow: str, base_path: str | Path = get_config_value("data", Path)
89
+ ) -> Result | None:
68
90
  base_path = Path(base_path)
69
91
  path = get_head(workflow, base_path)
70
92
  if path is None:
71
93
  return None
72
- with open(base_path / 'objects' / path, "rb") as f:
73
- return pickle.load(f)
94
+ return load_result(path, base_path)
74
95
 
75
96
 
76
97
  def renew_result(workflow: str, base_path: str | Path):
@@ -115,33 +136,56 @@ def get_head(workflow: str, base_path: str | Path) -> Path | None:
115
136
  return None
116
137
 
117
138
 
118
- def get_graph(base_path: str | Path) -> dict[str, list[str]]:
139
+ def get_heads(base_path: str | Path) -> Path | None:
119
140
  base_path = Path(base_path)
120
141
  try:
121
142
  with open(base_path / "heads", "rb") as f:
122
143
  heads = pickle.load(f)
144
+ return heads
123
145
  except:
124
- heads = {}
125
- graph = {}
126
- for workflow, path in heads.items():
127
- graph[workflow] = []
128
- while path is not None:
129
- with open(base_path / 'objects' / path, "rb") as f:
130
- result = pickle.load(f)
131
- path = result.previous
132
- if path is not None:
133
- graph[workflow].append(path)
134
- return graph
135
-
136
-
137
- def update_graph(workflow: str, base_path: str | Path):
138
- base_path = Path(base_path)
139
- graph = get_graph(base_path)
140
- for workflow, deps in graph.items():
141
- for dep in deps:
142
- if dep not in graph:
143
- graph[dep] = []
144
- if workflow not in graph[dep]:
145
- graph[dep].append(workflow)
146
- with open(base_path / "graph", "wb") as f:
147
- pickle.dump(graph, f)
146
+ return {}
147
+
148
+
149
+ def create_index(name: str,
150
+ base_path: str | Path,
151
+ context: str,
152
+ width: int,
153
+ start: int = 0):
154
+ path = Path(base_path) / "index" / f"{name}.seq"
155
+ if path.exists():
156
+ with open(path, "r") as f:
157
+ index = int(f.read())
158
+ else:
159
+ index = start
160
+ path.parent.mkdir(parents=True, exist_ok=True)
161
+ with open(path, "w") as f:
162
+ f.write(str(index + 1))
163
+
164
+ path = Path(base_path) / "index" / f"{name}.width"
165
+ with open(path, "w") as f:
166
+ f.write(str(width))
167
+
168
+ path = Path(base_path) / "index" / f"{name}.idx"
169
+ with open(path, "a") as f:
170
+
171
+ f.write(f"{context.ljust(width)}\n")
172
+
173
+ return index
174
+
175
+
176
+ def query_index(name: str, base_path: str | Path, index: int):
177
+ path = Path(base_path) / "index" / f"{name}.width"
178
+ with open(path, "r") as f:
179
+ width = int(f.read())
180
+ path = Path(base_path) / "index" / f"{name}.idx"
181
+ with open(path, "r") as f:
182
+ f.seek(index * (width + 1))
183
+ context = f.read(width)
184
+ return context.rstrip()
185
+
186
+
187
+ def get_result_by_index(
188
+ index: int, base_path: str | Path = get_config_value("data", Path)
189
+ ) -> Result | None:
190
+ path = query_index("result", base_path, index)
191
+ return load_result(path, base_path)
qulab/executor/utils.py CHANGED
@@ -31,10 +31,9 @@ def dependent_tree(node: str, code_path: str | Path) -> dict[str, list[str]]:
31
31
 
32
32
 
33
33
  def workflow_template(deps: list[str]) -> str:
34
- return f"""
35
- from loguru import logger
34
+ return f"""from loguru import logger
36
35
 
37
- def VAR(s): pass
36
+ def VAR(s): pass # 没有实际作用,只是用来抑制编辑器的警告。
38
37
 
39
38
  import numpy as np
40
39
 
Binary file
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.4.20"
1
+ __version__ = "2.5.0"
File without changes