siliconcompiler 0.34.2__py3-none-any.whl → 0.34.3__py3-none-any.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.
- siliconcompiler/__init__.py +12 -5
- siliconcompiler/__main__.py +1 -7
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/_common.py +104 -23
- siliconcompiler/apps/sc.py +4 -8
- siliconcompiler/apps/sc_dashboard.py +6 -4
- siliconcompiler/apps/sc_install.py +10 -6
- siliconcompiler/apps/sc_issue.py +7 -5
- siliconcompiler/apps/sc_remote.py +1 -1
- siliconcompiler/apps/sc_server.py +9 -14
- siliconcompiler/apps/sc_show.py +6 -5
- siliconcompiler/apps/smake.py +130 -94
- siliconcompiler/apps/utils/replay.py +4 -7
- siliconcompiler/apps/utils/summarize.py +3 -5
- siliconcompiler/asic.py +420 -0
- siliconcompiler/checklist.py +25 -2
- siliconcompiler/cmdlineschema.py +534 -0
- siliconcompiler/constraints/asic_component.py +2 -2
- siliconcompiler/constraints/asic_pins.py +2 -2
- siliconcompiler/constraints/asic_timing.py +3 -3
- siliconcompiler/core.py +7 -32
- siliconcompiler/data/templates/tcl/manifest.tcl.j2 +8 -0
- siliconcompiler/dependencyschema.py +89 -31
- siliconcompiler/design.py +176 -207
- siliconcompiler/filesetschema.py +250 -0
- siliconcompiler/flowgraph.py +274 -95
- siliconcompiler/fpga.py +124 -1
- siliconcompiler/library.py +218 -20
- siliconcompiler/metric.py +233 -20
- siliconcompiler/package/__init__.py +271 -50
- siliconcompiler/package/git.py +92 -16
- siliconcompiler/package/github.py +108 -12
- siliconcompiler/package/https.py +79 -16
- siliconcompiler/packageschema.py +88 -7
- siliconcompiler/pathschema.py +31 -2
- siliconcompiler/pdk.py +566 -1
- siliconcompiler/project.py +1095 -94
- siliconcompiler/record.py +38 -1
- siliconcompiler/remote/__init__.py +5 -2
- siliconcompiler/remote/client.py +11 -6
- siliconcompiler/remote/schema.py +5 -23
- siliconcompiler/remote/server.py +41 -54
- siliconcompiler/report/__init__.py +3 -3
- siliconcompiler/report/dashboard/__init__.py +48 -14
- siliconcompiler/report/dashboard/cli/__init__.py +99 -21
- siliconcompiler/report/dashboard/cli/board.py +364 -179
- siliconcompiler/report/dashboard/web/__init__.py +90 -12
- siliconcompiler/report/dashboard/web/components/__init__.py +219 -240
- siliconcompiler/report/dashboard/web/components/flowgraph.py +49 -26
- siliconcompiler/report/dashboard/web/components/graph.py +139 -100
- siliconcompiler/report/dashboard/web/layouts/__init__.py +29 -1
- siliconcompiler/report/dashboard/web/layouts/_common.py +38 -2
- siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph.py +39 -26
- siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_node_tab.py +50 -50
- siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_sac_tabs.py +49 -46
- siliconcompiler/report/dashboard/web/state.py +141 -14
- siliconcompiler/report/dashboard/web/utils/__init__.py +79 -16
- siliconcompiler/report/dashboard/web/utils/file_utils.py +74 -11
- siliconcompiler/report/dashboard/web/viewer.py +25 -1
- siliconcompiler/report/report.py +5 -2
- siliconcompiler/report/summary_image.py +29 -11
- siliconcompiler/scheduler/__init__.py +9 -1
- siliconcompiler/scheduler/docker.py +79 -1
- siliconcompiler/scheduler/run_node.py +35 -19
- siliconcompiler/scheduler/scheduler.py +208 -24
- siliconcompiler/scheduler/schedulernode.py +372 -46
- siliconcompiler/scheduler/send_messages.py +77 -29
- siliconcompiler/scheduler/slurm.py +76 -12
- siliconcompiler/scheduler/taskscheduler.py +140 -20
- siliconcompiler/schema/__init__.py +0 -2
- siliconcompiler/schema/baseschema.py +194 -38
- siliconcompiler/schema/journal.py +7 -4
- siliconcompiler/schema/namedschema.py +16 -10
- siliconcompiler/schema/parameter.py +55 -9
- siliconcompiler/schema/parametervalue.py +60 -0
- siliconcompiler/schema/safeschema.py +25 -2
- siliconcompiler/schema/schema_cfg.py +5 -5
- siliconcompiler/schema/utils.py +2 -2
- siliconcompiler/schema_obj.py +20 -3
- siliconcompiler/tool.py +979 -302
- siliconcompiler/tools/bambu/__init__.py +41 -0
- siliconcompiler/tools/builtin/concatenate.py +2 -2
- siliconcompiler/tools/builtin/minimum.py +2 -1
- siliconcompiler/tools/builtin/mux.py +2 -1
- siliconcompiler/tools/builtin/nop.py +2 -1
- siliconcompiler/tools/builtin/verify.py +2 -1
- siliconcompiler/tools/klayout/__init__.py +95 -0
- siliconcompiler/tools/openroad/__init__.py +289 -0
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -0
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +7 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +8 -4
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +9 -5
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +5 -1
- siliconcompiler/tools/slang/__init__.py +1 -1
- siliconcompiler/tools/slang/elaborate.py +2 -1
- siliconcompiler/tools/vivado/scripts/sc_run.tcl +1 -1
- siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +8 -1
- siliconcompiler/tools/vivado/syn_fpga.py +6 -0
- siliconcompiler/tools/vivado/vivado.py +35 -2
- siliconcompiler/tools/vpr/__init__.py +150 -0
- siliconcompiler/tools/yosys/__init__.py +369 -1
- siliconcompiler/tools/yosys/scripts/procs.tcl +0 -1
- siliconcompiler/toolscripts/_tools.json +5 -10
- siliconcompiler/utils/__init__.py +66 -0
- siliconcompiler/utils/flowgraph.py +2 -2
- siliconcompiler/utils/issue.py +2 -1
- siliconcompiler/utils/logging.py +14 -0
- siliconcompiler/utils/multiprocessing.py +256 -0
- siliconcompiler/utils/showtools.py +10 -0
- {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/METADATA +5 -5
- {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/RECORD +115 -118
- {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/entry_points.txt +3 -0
- siliconcompiler/schema/cmdlineschema.py +0 -250
- siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -40
- siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -40
- siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -47
- siliconcompiler/toolscripts/ubuntu22/install-slang.sh +0 -37
- siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -37
- {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/top_level.txt +0 -0
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import contextlib
|
|
8
8
|
import copy
|
|
9
|
+
import importlib
|
|
10
|
+
import logging
|
|
9
11
|
|
|
10
12
|
try:
|
|
11
13
|
import gzip
|
|
@@ -22,6 +24,9 @@ except ModuleNotFoundError:
|
|
|
22
24
|
|
|
23
25
|
import os.path
|
|
24
26
|
|
|
27
|
+
from functools import cache
|
|
28
|
+
from typing import Dict, Type, Tuple, Union, Set, Callable, List
|
|
29
|
+
|
|
25
30
|
from .parameter import Parameter, NodeValue
|
|
26
31
|
from .journal import Journal
|
|
27
32
|
|
|
@@ -49,7 +54,88 @@ class BaseSchema:
|
|
|
49
54
|
return tuple()
|
|
50
55
|
return tuple([*self.__parent._keypath, self.__key])
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
@staticmethod
|
|
58
|
+
@cache
|
|
59
|
+
def __get_child_classes() -> Dict[str, Type["BaseSchema"]]:
|
|
60
|
+
"""
|
|
61
|
+
Returns all known subclasses of BaseSchema
|
|
62
|
+
"""
|
|
63
|
+
def recurse(cls):
|
|
64
|
+
subclss = set()
|
|
65
|
+
subclss.add(cls)
|
|
66
|
+
for subcls in cls.__subclasses__():
|
|
67
|
+
subclss.update(recurse(subcls))
|
|
68
|
+
return subclss
|
|
69
|
+
|
|
70
|
+
# Resolve true base
|
|
71
|
+
cls_mapping = {}
|
|
72
|
+
for cls in recurse(BaseSchema):
|
|
73
|
+
try:
|
|
74
|
+
cls_mapping.setdefault(cls._getdict_type(), set()).add(cls)
|
|
75
|
+
except NotImplementedError:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
# Build lookup table
|
|
79
|
+
cls_map = {}
|
|
80
|
+
for cls_type, clss in cls_mapping.items():
|
|
81
|
+
for cls in clss:
|
|
82
|
+
cls_map[f"{cls.__module__}/{cls.__name__}"] = cls
|
|
83
|
+
|
|
84
|
+
if len(clss) > 1:
|
|
85
|
+
found = False
|
|
86
|
+
for cls in clss:
|
|
87
|
+
if cls.__name__ == cls_type:
|
|
88
|
+
cls_map[cls_type] = cls
|
|
89
|
+
found = True
|
|
90
|
+
break
|
|
91
|
+
if not found:
|
|
92
|
+
raise RuntimeError(f"fatal error at: {cls_type}")
|
|
93
|
+
else:
|
|
94
|
+
cls_map[cls_type] = list(clss)[0]
|
|
95
|
+
return cls_map
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
@cache
|
|
99
|
+
def __load_schema_class(cls_name: str) -> Type["BaseSchema"]:
|
|
100
|
+
"""
|
|
101
|
+
Load a schema class from a string
|
|
102
|
+
"""
|
|
103
|
+
try:
|
|
104
|
+
module_name, cls_name = cls_name.split("/")
|
|
105
|
+
except (ValueError, AttributeError):
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
module = importlib.import_module(module_name)
|
|
110
|
+
except (ImportError, ModuleNotFoundError, SyntaxError):
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
cls = getattr(module, cls_name, None)
|
|
114
|
+
if not cls:
|
|
115
|
+
return None
|
|
116
|
+
if not issubclass(cls, BaseSchema):
|
|
117
|
+
raise TypeError(f"{cls_name} must be a BaseSchema type")
|
|
118
|
+
return cls
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def __process_meta_section(meta: Dict[str, str]) -> Type["BaseSchema"]:
|
|
122
|
+
"""
|
|
123
|
+
Handle __meta__ section of the schema by loading the appropriate class
|
|
124
|
+
"""
|
|
125
|
+
cls_map = BaseSchema.__get_child_classes()
|
|
126
|
+
|
|
127
|
+
# Lookup object, use class first, then type
|
|
128
|
+
cls_name = meta.get("class", None)
|
|
129
|
+
cls = None
|
|
130
|
+
if cls_name:
|
|
131
|
+
cls = cls_map.get(cls_name, None)
|
|
132
|
+
if not cls:
|
|
133
|
+
cls = BaseSchema.__load_schema_class(cls_name)
|
|
134
|
+
if not cls:
|
|
135
|
+
cls = cls_map.get(meta.get("sctype", None), None)
|
|
136
|
+
return cls
|
|
137
|
+
|
|
138
|
+
def _from_dict(self, manifest: Dict, keypath: Tuple[str], version: str = None):
|
|
53
139
|
'''
|
|
54
140
|
Decodes a dictionary into a schema object
|
|
55
141
|
|
|
@@ -64,6 +150,10 @@ class BaseSchema:
|
|
|
64
150
|
|
|
65
151
|
if "__journal__" in manifest:
|
|
66
152
|
self.__journal.from_dict(manifest["__journal__"])
|
|
153
|
+
del manifest["__journal__"]
|
|
154
|
+
|
|
155
|
+
if "__meta__" in manifest:
|
|
156
|
+
del manifest["__meta__"]
|
|
67
157
|
|
|
68
158
|
if self.__default:
|
|
69
159
|
data = manifest.get("default", None)
|
|
@@ -74,9 +164,25 @@ class BaseSchema:
|
|
|
74
164
|
|
|
75
165
|
for key, data in manifest.items():
|
|
76
166
|
obj = self.__manifest.get(key, None)
|
|
167
|
+
if not obj and isinstance(data, dict) and "__meta__" in data:
|
|
168
|
+
# Lookup object, use class first, then type
|
|
169
|
+
cls = BaseSchema.__process_meta_section(data["__meta__"])
|
|
170
|
+
if cls is BaseSchema and self.__default:
|
|
171
|
+
# Use default when BaseSchema is the class
|
|
172
|
+
obj = self.__default.copy(key=keypath + [key])
|
|
173
|
+
self.__manifest[key] = obj
|
|
174
|
+
elif cls:
|
|
175
|
+
# Create object and connect to schema
|
|
176
|
+
obj = cls()
|
|
177
|
+
obj.__parent = self
|
|
178
|
+
obj.__key = key
|
|
179
|
+
self.__manifest[key] = obj
|
|
180
|
+
|
|
181
|
+
# Use default if it is available
|
|
77
182
|
if not obj and self.__default:
|
|
78
|
-
obj = self.__default.copy()
|
|
183
|
+
obj = self.__default.copy(key=keypath + [key])
|
|
79
184
|
self.__manifest[key] = obj
|
|
185
|
+
|
|
80
186
|
if obj:
|
|
81
187
|
obj._from_dict(data, keypath + [key], version=version)
|
|
82
188
|
handled.add(key)
|
|
@@ -87,7 +193,7 @@ class BaseSchema:
|
|
|
87
193
|
|
|
88
194
|
# Manifest methods
|
|
89
195
|
@classmethod
|
|
90
|
-
def from_manifest(cls, filepath=None, cfg=None):
|
|
196
|
+
def from_manifest(cls, filepath: str = None, cfg: Dict = None) -> "BaseSchema":
|
|
91
197
|
'''
|
|
92
198
|
Create a new schema based on the provided source files.
|
|
93
199
|
|
|
@@ -101,15 +207,24 @@ class BaseSchema:
|
|
|
101
207
|
if not filepath and cfg is None:
|
|
102
208
|
raise RuntimeError("filepath or dictionary is required")
|
|
103
209
|
|
|
104
|
-
schema = cls()
|
|
105
210
|
if filepath:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
211
|
+
cfg = BaseSchema._read_manifest(filepath)
|
|
212
|
+
|
|
213
|
+
new_cls = None
|
|
214
|
+
if "__meta__" in cfg:
|
|
215
|
+
# Determine correct class
|
|
216
|
+
new_cls = BaseSchema.__process_meta_section(cfg["__meta__"])
|
|
217
|
+
if new_cls:
|
|
218
|
+
schema = new_cls()
|
|
219
|
+
else:
|
|
220
|
+
schema = cls()
|
|
221
|
+
|
|
222
|
+
schema._from_dict(cfg, [])
|
|
223
|
+
|
|
109
224
|
return schema
|
|
110
225
|
|
|
111
226
|
@staticmethod
|
|
112
|
-
def __open_file(filepath, is_read=True):
|
|
227
|
+
def __open_file(filepath: str, is_read: bool = True):
|
|
113
228
|
_, ext = os.path.splitext(filepath)
|
|
114
229
|
if ext.lower() == ".gz":
|
|
115
230
|
if not _has_gzip:
|
|
@@ -117,10 +232,27 @@ class BaseSchema:
|
|
|
117
232
|
return gzip.open(filepath, mode="rt" if is_read else "wt", encoding="utf-8")
|
|
118
233
|
return open(filepath, mode="r" if is_read else "w", encoding="utf-8")
|
|
119
234
|
|
|
120
|
-
def __format_key(self, *key):
|
|
235
|
+
def __format_key(self, *key: str):
|
|
121
236
|
return f"[{','.join([*self._keypath, *key])}]"
|
|
122
237
|
|
|
123
|
-
|
|
238
|
+
@staticmethod
|
|
239
|
+
def _read_manifest(filepath: str):
|
|
240
|
+
"""
|
|
241
|
+
Reads a manifest from disk and returns dictionary.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
filename (path): Path to a manifest file to be loaded.
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
fin = BaseSchema.__open_file(filepath)
|
|
248
|
+
try:
|
|
249
|
+
manifest = json.loads(fin.read())
|
|
250
|
+
finally:
|
|
251
|
+
fin.close()
|
|
252
|
+
|
|
253
|
+
return manifest
|
|
254
|
+
|
|
255
|
+
def read_manifest(self, filepath: str):
|
|
124
256
|
"""
|
|
125
257
|
Reads a manifest from disk and replaces the current data with the data in the file.
|
|
126
258
|
|
|
@@ -132,13 +264,9 @@ class BaseSchema:
|
|
|
132
264
|
Loads the file mychip.json into the current Schema object.
|
|
133
265
|
"""
|
|
134
266
|
|
|
135
|
-
|
|
136
|
-
manifest = json.loads(fin.read())
|
|
137
|
-
fin.close()
|
|
138
|
-
|
|
139
|
-
self._from_dict(manifest, [])
|
|
267
|
+
self._from_dict(BaseSchema._read_manifest(filepath), [])
|
|
140
268
|
|
|
141
|
-
def write_manifest(self, filepath):
|
|
269
|
+
def write_manifest(self, filepath: str):
|
|
142
270
|
'''
|
|
143
271
|
Writes the manifest to a file.
|
|
144
272
|
|
|
@@ -162,11 +290,11 @@ class BaseSchema:
|
|
|
162
290
|
|
|
163
291
|
# Accessor methods
|
|
164
292
|
def __search(self,
|
|
165
|
-
*keypath,
|
|
166
|
-
insert_defaults=False,
|
|
167
|
-
use_default=False,
|
|
168
|
-
require_leaf=True,
|
|
169
|
-
complete_path=None):
|
|
293
|
+
*keypath: str,
|
|
294
|
+
insert_defaults: bool = False,
|
|
295
|
+
use_default: bool = False,
|
|
296
|
+
require_leaf: bool = True,
|
|
297
|
+
complete_path: bool = None) -> Union["BaseSchema", Parameter]:
|
|
170
298
|
if len(keypath) == 0:
|
|
171
299
|
if require_leaf:
|
|
172
300
|
raise KeyError
|
|
@@ -204,7 +332,8 @@ class BaseSchema:
|
|
|
204
332
|
complete_path=complete_path)
|
|
205
333
|
return key_param
|
|
206
334
|
|
|
207
|
-
def get(self, *keypath, field='value',
|
|
335
|
+
def get(self, *keypath: str, field: str = 'value',
|
|
336
|
+
step: str = None, index: Union[int, str] = None):
|
|
208
337
|
"""
|
|
209
338
|
Returns a parameter field from the schema.
|
|
210
339
|
|
|
@@ -260,7 +389,8 @@ class BaseSchema:
|
|
|
260
389
|
e.args = (new_msg, *e.args[1:])
|
|
261
390
|
raise e
|
|
262
391
|
|
|
263
|
-
def set(self, *args, field='value', clobber=True,
|
|
392
|
+
def set(self, *args: str, field: str = 'value', clobber: bool = True,
|
|
393
|
+
step: str = None, index: Union[int, str] = None):
|
|
264
394
|
'''
|
|
265
395
|
Sets a schema parameter field.
|
|
266
396
|
|
|
@@ -305,7 +435,8 @@ class BaseSchema:
|
|
|
305
435
|
e.args = (new_msg, *e.args[1:])
|
|
306
436
|
raise e
|
|
307
437
|
|
|
308
|
-
def add(self, *args, field='value',
|
|
438
|
+
def add(self, *args: str, field: str = 'value',
|
|
439
|
+
step: str = None, index: Union[int, str] = None):
|
|
309
440
|
'''
|
|
310
441
|
Adds item(s) to a schema parameter list.
|
|
311
442
|
|
|
@@ -348,7 +479,7 @@ class BaseSchema:
|
|
|
348
479
|
e.args = (new_msg, *e.args[1:])
|
|
349
480
|
raise e
|
|
350
481
|
|
|
351
|
-
def unset(self, *keypath, step=None, index=None):
|
|
482
|
+
def unset(self, *keypath: str, step: str = None, index: Union[int, str] = None):
|
|
352
483
|
'''
|
|
353
484
|
Unsets a schema parameter.
|
|
354
485
|
|
|
@@ -387,7 +518,7 @@ class BaseSchema:
|
|
|
387
518
|
e.args = (new_msg, *e.args[1:])
|
|
388
519
|
raise e
|
|
389
520
|
|
|
390
|
-
def remove(self, *keypath):
|
|
521
|
+
def remove(self, *keypath: str):
|
|
391
522
|
'''
|
|
392
523
|
Remove a schema parameter and its subparameters.
|
|
393
524
|
|
|
@@ -417,7 +548,8 @@ class BaseSchema:
|
|
|
417
548
|
del key_param.__manifest[removal_key]
|
|
418
549
|
self.__journal.record("remove", keypath)
|
|
419
550
|
|
|
420
|
-
def valid(self, *keypath, default_valid=False,
|
|
551
|
+
def valid(self, *keypath: str, default_valid: bool = False,
|
|
552
|
+
check_complete: bool = False) -> bool:
|
|
421
553
|
"""
|
|
422
554
|
Checks validity of a keypath.
|
|
423
555
|
|
|
@@ -451,7 +583,7 @@ class BaseSchema:
|
|
|
451
583
|
return isinstance(param, Parameter)
|
|
452
584
|
return True
|
|
453
585
|
|
|
454
|
-
def getkeys(self, *keypath):
|
|
586
|
+
def getkeys(self, *keypath: str) -> Tuple[str]:
|
|
455
587
|
"""
|
|
456
588
|
Returns a tuple of schema dictionary keys.
|
|
457
589
|
|
|
@@ -481,7 +613,7 @@ class BaseSchema:
|
|
|
481
613
|
|
|
482
614
|
return tuple(sorted(key_param.__manifest.keys()))
|
|
483
615
|
|
|
484
|
-
def allkeys(self, *keypath, include_default=True):
|
|
616
|
+
def allkeys(self, *keypath: str, include_default: bool = True) -> Set[Tuple[str]]:
|
|
485
617
|
'''
|
|
486
618
|
Returns all keypaths in the schema as a set of tuples.
|
|
487
619
|
|
|
@@ -510,7 +642,16 @@ class BaseSchema:
|
|
|
510
642
|
add(keys, key, item)
|
|
511
643
|
return set(keys)
|
|
512
644
|
|
|
513
|
-
|
|
645
|
+
@classmethod
|
|
646
|
+
def _getdict_type(cls) -> str:
|
|
647
|
+
"""
|
|
648
|
+
Returns the meta data for getdict
|
|
649
|
+
"""
|
|
650
|
+
|
|
651
|
+
return "BaseSchema"
|
|
652
|
+
|
|
653
|
+
def getdict(self, *keypath: str, include_default: bool = True,
|
|
654
|
+
values_only: bool = False) -> Dict:
|
|
514
655
|
"""
|
|
515
656
|
Returns a schema dictionary.
|
|
516
657
|
|
|
@@ -553,10 +694,19 @@ class BaseSchema:
|
|
|
553
694
|
if not values_only and self.__journal.has_journaling():
|
|
554
695
|
manifest["__journal__"] = self.__journal.get()
|
|
555
696
|
|
|
697
|
+
if not values_only and self.__class__ is not BaseSchema:
|
|
698
|
+
manifest["__meta__"] = {
|
|
699
|
+
"class": f"{self.__class__.__module__}/{self.__class__.__name__}"
|
|
700
|
+
}
|
|
701
|
+
try:
|
|
702
|
+
manifest["__meta__"]["sctype"] = self._getdict_type()
|
|
703
|
+
except NotImplementedError:
|
|
704
|
+
pass
|
|
705
|
+
|
|
556
706
|
return manifest
|
|
557
707
|
|
|
558
708
|
# Utility functions
|
|
559
|
-
def copy(self, key=None):
|
|
709
|
+
def copy(self, key: Tuple[str] = None):
|
|
560
710
|
"""
|
|
561
711
|
Returns a copy of this schema.
|
|
562
712
|
|
|
@@ -579,7 +729,7 @@ class BaseSchema:
|
|
|
579
729
|
|
|
580
730
|
return schema_copy
|
|
581
731
|
|
|
582
|
-
def _find_files_search_paths(self, keypath, step, index):
|
|
732
|
+
def _find_files_search_paths(self, keypath: Tuple[str], step: str, index: str):
|
|
583
733
|
"""
|
|
584
734
|
Returns a list of paths to search during find files.
|
|
585
735
|
|
|
@@ -601,8 +751,11 @@ class BaseSchema:
|
|
|
601
751
|
return {}
|
|
602
752
|
return self.__parent._find_files_dataroot_resolvers()
|
|
603
753
|
|
|
604
|
-
def find_files(self, *keypath, missing_ok
|
|
605
|
-
|
|
754
|
+
def find_files(self, *keypath: str, missing_ok: bool = False,
|
|
755
|
+
step: str = None, index: Union[int, str] = None,
|
|
756
|
+
packages: Dict[str, Union[str, Callable]] = None,
|
|
757
|
+
collection_dir: str = None,
|
|
758
|
+
cwd: str = None) -> Union[str, List[str], Set[str]]:
|
|
606
759
|
"""
|
|
607
760
|
Returns absolute paths to files or directories based on the keypath
|
|
608
761
|
provided.
|
|
@@ -707,8 +860,11 @@ class BaseSchema:
|
|
|
707
860
|
return resolved_paths[0]
|
|
708
861
|
return resolved_paths
|
|
709
862
|
|
|
710
|
-
def check_filepaths(self, ignore_keys=
|
|
711
|
-
|
|
863
|
+
def check_filepaths(self, ignore_keys: bool = None,
|
|
864
|
+
logger: logging.Logger = None,
|
|
865
|
+
packages: Dict[str, Union[str, Callable]] = None,
|
|
866
|
+
collection_dir: str = None,
|
|
867
|
+
cwd: str = None) -> bool:
|
|
712
868
|
'''
|
|
713
869
|
Verifies that paths to all files in manifest are valid.
|
|
714
870
|
|
|
@@ -773,7 +929,7 @@ class BaseSchema:
|
|
|
773
929
|
|
|
774
930
|
return not error
|
|
775
931
|
|
|
776
|
-
def _parent(self, root=False):
|
|
932
|
+
def _parent(self, root: bool = False) -> "BaseSchema":
|
|
777
933
|
'''
|
|
778
934
|
Returns the parent of this schema section, if root is true the root parent
|
|
779
935
|
will be returned.
|
|
@@ -815,7 +971,7 @@ class BaseSchema:
|
|
|
815
971
|
finally:
|
|
816
972
|
self.__active = orig_active
|
|
817
973
|
|
|
818
|
-
def _get_active(self, field, defvalue=None):
|
|
974
|
+
def _get_active(self, field: str, defvalue=None):
|
|
819
975
|
'''
|
|
820
976
|
Get the value of a specific field.
|
|
821
977
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
|
-
from typing import Tuple, Set
|
|
4
|
+
from typing import Tuple, Set, Dict, List
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Journal:
|
|
@@ -45,7 +45,7 @@ class Journal:
|
|
|
45
45
|
child.__parent = self.__parent
|
|
46
46
|
return child
|
|
47
47
|
|
|
48
|
-
def from_dict(self, manifest):
|
|
48
|
+
def from_dict(self, manifest: Dict):
|
|
49
49
|
'''
|
|
50
50
|
Import a journal from a manifest dictionary
|
|
51
51
|
|
|
@@ -55,7 +55,7 @@ class Journal:
|
|
|
55
55
|
|
|
56
56
|
self.__journal = manifest
|
|
57
57
|
|
|
58
|
-
def get(self):
|
|
58
|
+
def get(self) -> List[Dict]:
|
|
59
59
|
"""
|
|
60
60
|
Returns a copy of the current journal
|
|
61
61
|
"""
|
|
@@ -124,6 +124,9 @@ class Journal:
|
|
|
124
124
|
if record_type not in self.__parent.__record_types:
|
|
125
125
|
return
|
|
126
126
|
|
|
127
|
+
if isinstance(value, set):
|
|
128
|
+
value = list(value)
|
|
129
|
+
|
|
127
130
|
self.__parent.__journal.append({
|
|
128
131
|
"type": record_type,
|
|
129
132
|
"key": tuple([*self.__keyprefix, *key]),
|
|
@@ -204,7 +207,7 @@ class Journal:
|
|
|
204
207
|
raise ValueError(f'Unknown record type {record_type}')
|
|
205
208
|
|
|
206
209
|
@staticmethod
|
|
207
|
-
def access(schema) ->
|
|
210
|
+
def access(schema) -> "Journal":
|
|
208
211
|
'''
|
|
209
212
|
Access a journal from a schema
|
|
210
213
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
# SC dependencies outside of its directory, since it may be used by tool drivers
|
|
5
5
|
# that have isolated Python environments.
|
|
6
6
|
|
|
7
|
+
from typing import Dict, Tuple
|
|
8
|
+
|
|
7
9
|
from .baseschema import BaseSchema
|
|
8
10
|
|
|
9
11
|
|
|
@@ -20,6 +22,7 @@ class NamedSchema(BaseSchema):
|
|
|
20
22
|
|
|
21
23
|
self.set_name(name)
|
|
22
24
|
|
|
25
|
+
@property
|
|
23
26
|
def name(self) -> str:
|
|
24
27
|
'''
|
|
25
28
|
Returns the name of the schema
|
|
@@ -40,26 +43,28 @@ class NamedSchema(BaseSchema):
|
|
|
40
43
|
name (str): name for object
|
|
41
44
|
"""
|
|
42
45
|
|
|
43
|
-
if self.name
|
|
46
|
+
if self.name is not None:
|
|
44
47
|
raise RuntimeError("Cannot call set_name more than once.")
|
|
45
48
|
if name is not None and "." in name:
|
|
46
49
|
raise ValueError("Named schema object cannot contains: .")
|
|
47
50
|
self.__name = name
|
|
48
51
|
|
|
49
|
-
def
|
|
52
|
+
def type(self) -> str:
|
|
50
53
|
"""
|
|
51
|
-
|
|
54
|
+
Returns the type of this object
|
|
52
55
|
"""
|
|
53
|
-
|
|
56
|
+
raise NotImplementedError("Must be implemented by the child classes.")
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
@classmethod
|
|
59
|
+
def _getdict_type(cls) -> str:
|
|
56
60
|
"""
|
|
57
|
-
Returns the
|
|
61
|
+
Returns the meta data for getdict
|
|
58
62
|
"""
|
|
63
|
+
|
|
59
64
|
raise NotImplementedError("Must be implemented by the child classes.")
|
|
60
65
|
|
|
61
66
|
@classmethod
|
|
62
|
-
def from_manifest(cls, name, filepath=None, cfg=None):
|
|
67
|
+
def from_manifest(cls, name: str, filepath: str = None, cfg: Dict = None):
|
|
63
68
|
'''
|
|
64
69
|
Create a new schema based on the provided source files.
|
|
65
70
|
|
|
@@ -74,20 +79,21 @@ class NamedSchema(BaseSchema):
|
|
|
74
79
|
if not filepath and cfg is None:
|
|
75
80
|
raise RuntimeError("filepath or dictionary is required")
|
|
76
81
|
|
|
77
|
-
schema = cls(
|
|
82
|
+
schema = cls()
|
|
83
|
+
schema.set_name(name)
|
|
78
84
|
if filepath:
|
|
79
85
|
schema.read_manifest(filepath)
|
|
80
86
|
if cfg:
|
|
81
87
|
schema._from_dict(cfg, [])
|
|
82
88
|
return schema
|
|
83
89
|
|
|
84
|
-
def _from_dict(self, manifest, keypath, version=None):
|
|
90
|
+
def _from_dict(self, manifest: Dict, keypath: Tuple[str], version: str = None):
|
|
85
91
|
if keypath:
|
|
86
92
|
self.__name = keypath[-1]
|
|
87
93
|
|
|
88
94
|
return super()._from_dict(manifest, keypath, version=version)
|
|
89
95
|
|
|
90
|
-
def copy(self, key=None):
|
|
96
|
+
def copy(self, key: Tuple[str] = None) -> "NamedSchema":
|
|
91
97
|
copy = super().copy(key=key)
|
|
92
98
|
|
|
93
99
|
if key and key[-1] != "default":
|
|
@@ -574,14 +574,27 @@ class Parameter:
|
|
|
574
574
|
|
|
575
575
|
if self.__pernode == PerNode.REQUIRED and (step is None or index is None):
|
|
576
576
|
return None
|
|
577
|
-
if not self.__pernode.is_never():
|
|
578
|
-
value = self.get(step=step, index=index)
|
|
579
|
-
else:
|
|
580
|
-
value = self.get()
|
|
581
577
|
|
|
582
|
-
|
|
578
|
+
if isinstance(index, int):
|
|
579
|
+
index = str(index)
|
|
583
580
|
|
|
584
|
-
|
|
581
|
+
try:
|
|
582
|
+
return self.__node[step][index].gettcl()
|
|
583
|
+
except KeyError:
|
|
584
|
+
if self.__pernode == PerNode.REQUIRED:
|
|
585
|
+
return self.__defvalue.gettcl()
|
|
586
|
+
|
|
587
|
+
try:
|
|
588
|
+
return self.__node[step][Parameter.GLOBAL_KEY].gettcl()
|
|
589
|
+
except KeyError:
|
|
590
|
+
pass
|
|
591
|
+
|
|
592
|
+
try:
|
|
593
|
+
return self.__node[Parameter.GLOBAL_KEY][Parameter.GLOBAL_KEY].gettcl()
|
|
594
|
+
except KeyError:
|
|
595
|
+
return self.__defvalue.gettcl()
|
|
596
|
+
|
|
597
|
+
def getvalues(self, return_defvalue=True, return_values=True):
|
|
585
598
|
"""
|
|
586
599
|
Returns all values (global and pernode) associated with a particular parameter.
|
|
587
600
|
|
|
@@ -599,10 +612,16 @@ class Parameter:
|
|
|
599
612
|
index_arg = None if index == Parameter.GLOBAL_KEY else index
|
|
600
613
|
if step_arg is None and index_arg is None:
|
|
601
614
|
has_global = True
|
|
602
|
-
|
|
615
|
+
if return_values:
|
|
616
|
+
vals.append((self.__node[step][index].get(), step_arg, index_arg))
|
|
617
|
+
else:
|
|
618
|
+
vals.append((self.__node[step][index], step_arg, index_arg))
|
|
603
619
|
|
|
604
|
-
if
|
|
605
|
-
|
|
620
|
+
if self.__pernode != PerNode.REQUIRED and not has_global and return_defvalue:
|
|
621
|
+
if return_values:
|
|
622
|
+
vals.append((self.__defvalue.get(), None, None))
|
|
623
|
+
else:
|
|
624
|
+
vals.append((self.__defvalue, None, None))
|
|
606
625
|
|
|
607
626
|
return vals
|
|
608
627
|
|
|
@@ -656,6 +675,33 @@ class Parameter:
|
|
|
656
675
|
index in self.__node[step] and \
|
|
657
676
|
self.__node[step][index]
|
|
658
677
|
|
|
678
|
+
def has_value(self, step=None, index=None) -> bool:
|
|
679
|
+
'''
|
|
680
|
+
Returns whether the parameter as a value.
|
|
681
|
+
|
|
682
|
+
A value counts as set if a user has set a global value OR a value for
|
|
683
|
+
the provided step/index.
|
|
684
|
+
'''
|
|
685
|
+
|
|
686
|
+
if isinstance(index, int):
|
|
687
|
+
index = str(index)
|
|
688
|
+
|
|
689
|
+
try:
|
|
690
|
+
return self.__node[step][index].has_value
|
|
691
|
+
except KeyError:
|
|
692
|
+
if self.__pernode == PerNode.REQUIRED:
|
|
693
|
+
return self.__defvalue.has_value
|
|
694
|
+
|
|
695
|
+
try:
|
|
696
|
+
return self.__node[step][Parameter.GLOBAL_KEY].has_value
|
|
697
|
+
except KeyError:
|
|
698
|
+
pass
|
|
699
|
+
|
|
700
|
+
try:
|
|
701
|
+
return self.__node[Parameter.GLOBAL_KEY][Parameter.GLOBAL_KEY].has_value
|
|
702
|
+
except KeyError:
|
|
703
|
+
return self.__defvalue.has_value
|
|
704
|
+
|
|
659
705
|
@property
|
|
660
706
|
def default(self):
|
|
661
707
|
"""
|