QuLab 2.4.20__tar.gz → 2.5.0__tar.gz

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.
Files changed (111) hide show
  1. {qulab-2.4.20 → qulab-2.5.0}/PKG-INFO +1 -1
  2. {qulab-2.4.20 → qulab-2.5.0}/QuLab.egg-info/PKG-INFO +1 -1
  3. {qulab-2.4.20 → qulab-2.5.0}/QuLab.egg-info/SOURCES.txt +1 -0
  4. {qulab-2.4.20 → qulab-2.5.0}/qulab/__init__.py +2 -0
  5. {qulab-2.4.20 → qulab-2.5.0}/qulab/__main__.py +1 -1
  6. {qulab-2.4.20 → qulab-2.5.0}/qulab/cli/config.py +23 -15
  7. {qulab-2.4.20 → qulab-2.5.0}/qulab/executor/load.py +1 -1
  8. {qulab-2.4.20 → qulab-2.5.0}/qulab/executor/schedule.py +11 -9
  9. qulab-2.5.0/qulab/executor/storage.py +191 -0
  10. {qulab-2.4.20 → qulab-2.5.0}/qulab/executor/utils.py +2 -3
  11. qulab-2.5.0/qulab/sys/rpc/worker.py +0 -0
  12. qulab-2.5.0/qulab/version.py +1 -0
  13. qulab-2.4.20/qulab/executor/storage.py +0 -147
  14. qulab-2.4.20/qulab/version.py +0 -1
  15. {qulab-2.4.20 → qulab-2.5.0}/LICENSE +0 -0
  16. {qulab-2.4.20 → qulab-2.5.0}/MANIFEST.in +0 -0
  17. {qulab-2.4.20 → qulab-2.5.0}/QuLab.egg-info/dependency_links.txt +0 -0
  18. {qulab-2.4.20 → qulab-2.5.0}/QuLab.egg-info/entry_points.txt +0 -0
  19. {qulab-2.4.20 → qulab-2.5.0}/QuLab.egg-info/requires.txt +0 -0
  20. {qulab-2.4.20 → qulab-2.5.0}/QuLab.egg-info/top_level.txt +0 -0
  21. {qulab-2.4.20 → qulab-2.5.0}/README.md +0 -0
  22. {qulab-2.4.20 → qulab-2.5.0}/pyproject.toml +0 -0
  23. {qulab-2.4.20/qulab/storage → qulab-2.5.0/qulab/cli}/__init__.py +0 -0
  24. /qulab-2.4.20/qulab/cli/__init__.py → /qulab-2.5.0/qulab/cli/commands.py +0 -0
  25. {qulab-2.4.20 → qulab-2.5.0}/qulab/dicttree.py +0 -0
  26. {qulab-2.4.20 → qulab-2.5.0}/qulab/executor/__init__.py +0 -0
  27. {qulab-2.4.20 → qulab-2.5.0}/qulab/executor/cli.py +0 -0
  28. {qulab-2.4.20 → qulab-2.5.0}/qulab/executor/transform.py +0 -0
  29. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/__init__.py +0 -0
  30. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/__main__.py +0 -0
  31. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/config.py +0 -0
  32. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/dataset.py +0 -0
  33. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/event_queue.py +0 -0
  34. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/mainwindow.py +0 -0
  35. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/monitor.py +0 -0
  36. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/ploter.py +0 -0
  37. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/qt_compat.py +0 -0
  38. {qulab-2.4.20 → qulab-2.5.0}/qulab/monitor/toolbar.py +0 -0
  39. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/__init__.py +0 -0
  40. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/curd.py +0 -0
  41. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/expression.py +0 -0
  42. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/models.py +0 -0
  43. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/optimize.py +0 -0
  44. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/query.py +0 -0
  45. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/record.py +0 -0
  46. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/scan.py +0 -0
  47. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/server.py +0 -0
  48. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/space.py +0 -0
  49. {qulab-2.4.20 → qulab-2.5.0}/qulab/scan/utils.py +0 -0
  50. {qulab-2.4.20/qulab/storage/backend → qulab-2.5.0/qulab/storage}/__init__.py +0 -0
  51. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/__main__.py +0 -0
  52. {qulab-2.4.20/qulab/sys → qulab-2.5.0/qulab/storage/backend}/__init__.py +0 -0
  53. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/backend/redis.py +0 -0
  54. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/base_dataset.py +0 -0
  55. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/chunk.py +0 -0
  56. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/dataset.py +0 -0
  57. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/file.py +0 -0
  58. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/__init__.py +0 -0
  59. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/base.py +0 -0
  60. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/config.py +0 -0
  61. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/file.py +0 -0
  62. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/ipy.py +0 -0
  63. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/models.py +0 -0
  64. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/record.py +0 -0
  65. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/report.py +0 -0
  66. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/models/tag.py +0 -0
  67. {qulab-2.4.20 → qulab-2.5.0}/qulab/storage/storage.py +0 -0
  68. {qulab-2.4.20/qulab/sys/drivers → qulab-2.5.0/qulab/sys}/__init__.py +0 -0
  69. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/chat.py +0 -0
  70. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/device/__init__.py +0 -0
  71. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/device/basedevice.py +0 -0
  72. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/device/loader.py +0 -0
  73. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/device/utils.py +0 -0
  74. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/drivers/FakeInstrument.py +0 -0
  75. {qulab-2.4.20/qulab/sys/net → qulab-2.5.0/qulab/sys/drivers}/__init__.py +0 -0
  76. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/ipy_events.py +0 -0
  77. {qulab-2.4.20/qulab/sys/rpc → qulab-2.5.0/qulab/sys/net}/__init__.py +0 -0
  78. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/bencoder.py +0 -0
  79. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/cli.py +0 -0
  80. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/dhcp.py +0 -0
  81. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/dhcpd.py +0 -0
  82. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/kad.py +0 -0
  83. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/kcp.py +0 -0
  84. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/net/nginx.py +0 -0
  85. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/progress.py +0 -0
  86. /qulab-2.4.20/qulab/sys/rpc/client.py → /qulab-2.5.0/qulab/sys/rpc/__init__.py +0 -0
  87. /qulab-2.4.20/qulab/sys/rpc/worker.py → /qulab-2.5.0/qulab/sys/rpc/client.py +0 -0
  88. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/exceptions.py +0 -0
  89. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/msgpack.py +0 -0
  90. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/msgpack.pyi +0 -0
  91. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/router.py +0 -0
  92. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/rpc.py +0 -0
  93. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/serialize.py +0 -0
  94. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/server.py +0 -0
  95. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/socket.py +0 -0
  96. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/utils.py +0 -0
  97. {qulab-2.4.20 → qulab-2.5.0}/qulab/sys/rpc/zmq_socket.py +0 -0
  98. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/__init__.py +0 -0
  99. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/__main__.py +0 -0
  100. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/_autoplot.py +0 -0
  101. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/plot_circ.py +0 -0
  102. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/plot_layout.py +0 -0
  103. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/plot_seq.py +0 -0
  104. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/qdat.py +0 -0
  105. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/rot3d.py +0 -0
  106. {qulab-2.4.20 → qulab-2.5.0}/qulab/visualization/widgets.py +0 -0
  107. {qulab-2.4.20 → qulab-2.5.0}/setup.cfg +0 -0
  108. {qulab-2.4.20 → qulab-2.5.0}/setup.py +0 -0
  109. {qulab-2.4.20 → qulab-2.5.0}/src/qulab.h +0 -0
  110. {qulab-2.4.20 → qulab-2.5.0}/tests/test_kad.py +0 -0
  111. {qulab-2.4.20 → qulab-2.5.0}/tests/test_scan.py +0 -0
@@ -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,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>
@@ -14,6 +14,7 @@ qulab/__main__.py
14
14
  qulab/dicttree.py
15
15
  qulab/version.py
16
16
  qulab/cli/__init__.py
17
+ qulab/cli/commands.py
17
18
  qulab/cli/config.py
18
19
  qulab/executor/__init__.py
19
20
  qulab/executor/cli.py
@@ -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
@@ -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()
@@ -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
@@ -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
 
@@ -0,0 +1,191 @@
1
+ import lzma
2
+ import pickle
3
+ import uuid
4
+ from dataclasses import dataclass, field
5
+ from datetime import datetime, timedelta
6
+ from pathlib import Path
7
+
8
+ from loguru import logger
9
+
10
+ from ..cli.config import get_config_value
11
+
12
+
13
+ @dataclass
14
+ class Result():
15
+ in_spec: bool = False
16
+ bad_data: bool = False
17
+ fully_calibrated: bool = False
18
+ calibrated_time: datetime = field(default_factory=datetime.now)
19
+ checked_time: datetime = field(default_factory=datetime.now)
20
+ ttl: timedelta = timedelta(days=3650)
21
+ params: dict = field(default_factory=dict)
22
+ info: dict = field(default_factory=dict)
23
+ data: tuple = field(default_factory=tuple)
24
+ index: int = -1
25
+ previous_path: Path | None = None
26
+ base_path: Path | None = None
27
+
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
34
+
35
+
36
+ def random_path(base: Path) -> Path:
37
+ while True:
38
+ s = uuid.uuid4().hex
39
+ path = Path(s[:2]) / s[2:4] / s[4:6] / s[6:]
40
+ if not (base / path).exists():
41
+ return path
42
+
43
+
44
+ def save_result(workflow: str,
45
+ result: Result,
46
+ base_path: str | Path,
47
+ overwrite: bool = False):
48
+ logger.debug(
49
+ f'Saving result for "{workflow}", {result.in_spec=}, {result.bad_data=}, {result.fully_calibrated=}'
50
+ )
51
+ base_path = Path(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
+
69
+ with open(base_path / 'objects' / path, "wb") as f:
70
+ f.write(result.index.to_bytes(8, 'big'))
71
+ f.write(buf)
72
+ set_head(workflow, path, base_path)
73
+
74
+
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:
90
+ base_path = Path(base_path)
91
+ path = get_head(workflow, base_path)
92
+ if path is None:
93
+ return None
94
+ return load_result(path, base_path)
95
+
96
+
97
+ def renew_result(workflow: str, base_path: str | Path):
98
+ logger.debug(f'Renewing result for "{workflow}"')
99
+ result = find_result(workflow, base_path)
100
+ if result is not None:
101
+ result.checked_time = datetime.now()
102
+ save_result(workflow, result, base_path)
103
+
104
+
105
+ def revoke_result(workflow: str, base_path: str | Path):
106
+ logger.debug(f'Revoking result for "{workflow}"')
107
+ base_path = Path(base_path)
108
+ path = get_head(workflow, base_path)
109
+ if path is not None:
110
+ with open(base_path / 'objects' / path, "rb") as f:
111
+ result = pickle.load(f)
112
+ result.in_spec = False
113
+ save_result(workflow, result, base_path)
114
+
115
+
116
+ def set_head(workflow: str, path: Path, base_path: str | Path):
117
+ base_path = Path(base_path)
118
+ base_path.mkdir(parents=True, exist_ok=True)
119
+ try:
120
+ with open(base_path / "heads", "rb") as f:
121
+ heads = pickle.load(f)
122
+ except:
123
+ heads = {}
124
+ heads[workflow] = path
125
+ with open(base_path / "heads", "wb") as f:
126
+ pickle.dump(heads, f)
127
+
128
+
129
+ def get_head(workflow: str, base_path: str | Path) -> Path | None:
130
+ base_path = Path(base_path)
131
+ try:
132
+ with open(base_path / "heads", "rb") as f:
133
+ heads = pickle.load(f)
134
+ return heads[workflow]
135
+ except:
136
+ return None
137
+
138
+
139
+ def get_heads(base_path: str | Path) -> Path | None:
140
+ base_path = Path(base_path)
141
+ try:
142
+ with open(base_path / "heads", "rb") as f:
143
+ heads = pickle.load(f)
144
+ return heads
145
+ except:
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)
@@ -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
 
File without changes
@@ -0,0 +1 @@
1
+ __version__ = "2.5.0"
@@ -1,147 +0,0 @@
1
- import pickle
2
- import uuid
3
- from dataclasses import dataclass, field
4
- from datetime import datetime, timedelta
5
- from pathlib import Path
6
-
7
- from loguru import logger
8
-
9
-
10
- @dataclass
11
- class Result():
12
- in_spec: bool = False
13
- bad_data: bool = False
14
- fully_calibrated: bool = False
15
- calibrated_time: datetime = field(default_factory=datetime.now)
16
- checked_time: datetime = field(default_factory=datetime.now)
17
- ttl: timedelta = timedelta(days=3650)
18
- params: dict = field(default_factory=dict)
19
- info: dict = field(default_factory=dict)
20
- 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()
30
-
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)
40
-
41
-
42
- def random_path(base: Path) -> Path:
43
- while True:
44
- s = uuid.uuid4().hex
45
- path = Path(s[:2]) / s[2:4] / s[4:6] / s[6:]
46
- if not (base / path).exists():
47
- return path
48
-
49
-
50
- def save_result(workflow: str,
51
- result: Result,
52
- base_path: str | Path,
53
- path: Path | None = None):
54
- logger.debug(
55
- f'Saving result for "{workflow}", {result.in_spec=}, {result.bad_data=}, {result.fully_calibrated=}'
56
- )
57
- 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)
62
- with open(base_path / 'objects' / path, "wb") as f:
63
- pickle.dump(result, f)
64
- set_head(workflow, path, base_path)
65
-
66
-
67
- def find_result(workflow: str, base_path: str | Path) -> Result | None:
68
- base_path = Path(base_path)
69
- path = get_head(workflow, base_path)
70
- if path is None:
71
- return None
72
- with open(base_path / 'objects' / path, "rb") as f:
73
- return pickle.load(f)
74
-
75
-
76
- def renew_result(workflow: str, base_path: str | Path):
77
- logger.debug(f'Renewing result for "{workflow}"')
78
- result = find_result(workflow, base_path)
79
- if result is not None:
80
- result.checked_time = datetime.now()
81
- save_result(workflow, result, base_path)
82
-
83
-
84
- def revoke_result(workflow: str, base_path: str | Path):
85
- logger.debug(f'Revoking result for "{workflow}"')
86
- base_path = Path(base_path)
87
- path = get_head(workflow, base_path)
88
- if path is not None:
89
- with open(base_path / 'objects' / path, "rb") as f:
90
- result = pickle.load(f)
91
- result.in_spec = False
92
- save_result(workflow, result, base_path)
93
-
94
-
95
- def set_head(workflow: str, path: Path, base_path: str | Path):
96
- base_path = Path(base_path)
97
- base_path.mkdir(parents=True, exist_ok=True)
98
- try:
99
- with open(base_path / "heads", "rb") as f:
100
- heads = pickle.load(f)
101
- except:
102
- heads = {}
103
- heads[workflow] = path
104
- with open(base_path / "heads", "wb") as f:
105
- pickle.dump(heads, f)
106
-
107
-
108
- def get_head(workflow: str, base_path: str | Path) -> Path | None:
109
- base_path = Path(base_path)
110
- try:
111
- with open(base_path / "heads", "rb") as f:
112
- heads = pickle.load(f)
113
- return heads[workflow]
114
- except:
115
- return None
116
-
117
-
118
- def get_graph(base_path: str | Path) -> dict[str, list[str]]:
119
- base_path = Path(base_path)
120
- try:
121
- with open(base_path / "heads", "rb") as f:
122
- heads = pickle.load(f)
123
- 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)
@@ -1 +0,0 @@
1
- __version__ = "2.4.20"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes