siliconcompiler 0.33.2__py3-none-any.whl → 0.34.0__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 +2 -0
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_issue.py +5 -3
- siliconcompiler/apps/sc_remote.py +0 -17
- siliconcompiler/checklist.py +1 -1
- siliconcompiler/core.py +34 -47
- siliconcompiler/dependencyschema.py +392 -0
- siliconcompiler/design.py +664 -0
- siliconcompiler/flowgraph.py +32 -1
- siliconcompiler/package/__init__.py +383 -223
- siliconcompiler/package/git.py +75 -77
- siliconcompiler/package/github.py +70 -97
- siliconcompiler/package/https.py +77 -93
- siliconcompiler/packageschema.py +260 -0
- siliconcompiler/pdk.py +2 -2
- siliconcompiler/remote/client.py +15 -3
- siliconcompiler/report/dashboard/cli/board.py +1 -1
- siliconcompiler/scheduler/__init__.py +3 -1382
- siliconcompiler/scheduler/docker.py +268 -0
- siliconcompiler/scheduler/run_node.py +10 -16
- siliconcompiler/scheduler/scheduler.py +308 -0
- siliconcompiler/scheduler/schedulernode.py +934 -0
- siliconcompiler/scheduler/slurm.py +147 -163
- siliconcompiler/scheduler/taskscheduler.py +39 -52
- siliconcompiler/schema/__init__.py +3 -3
- siliconcompiler/schema/baseschema.py +234 -10
- siliconcompiler/schema/editableschema.py +4 -0
- siliconcompiler/schema/journal.py +210 -0
- siliconcompiler/schema/namedschema.py +31 -2
- siliconcompiler/schema/parameter.py +14 -1
- siliconcompiler/schema/parametervalue.py +1 -34
- siliconcompiler/schema/schema_cfg.py +210 -349
- siliconcompiler/tool.py +61 -20
- siliconcompiler/tools/builtin/concatenate.py +2 -2
- siliconcompiler/tools/builtin/verify.py +1 -2
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +27 -25
- siliconcompiler/tools/vpr/route.py +69 -0
- siliconcompiler/toolscripts/_tools.json +4 -4
- siliconcompiler/utils/__init__.py +2 -23
- siliconcompiler/utils/flowgraph.py +5 -5
- siliconcompiler/utils/logging.py +2 -1
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.0.dist-info}/METADATA +4 -3
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.0.dist-info}/RECORD +47 -42
- siliconcompiler/scheduler/docker_runner.py +0 -254
- siliconcompiler/schema/journalingschema.py +0 -242
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.0.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.0.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.0.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.0.dist-info}/top_level.txt +0 -0
siliconcompiler/__init__.py
CHANGED
|
@@ -3,6 +3,7 @@ from siliconcompiler._common import NodeStatus, SiliconCompilerError
|
|
|
3
3
|
from siliconcompiler.utils import sc_open
|
|
4
4
|
from siliconcompiler.schema_obj import SchemaTmp as Schema
|
|
5
5
|
|
|
6
|
+
from siliconcompiler.design import DesignSchema
|
|
6
7
|
from siliconcompiler.record import RecordSchema
|
|
7
8
|
from siliconcompiler.metric import MetricSchema
|
|
8
9
|
from siliconcompiler.pdk import PDKSchema
|
|
@@ -30,6 +31,7 @@ __all__ = [
|
|
|
30
31
|
"Checklist",
|
|
31
32
|
"Schema",
|
|
32
33
|
"sc_open",
|
|
34
|
+
"DesignSchema",
|
|
33
35
|
"RecordSchema",
|
|
34
36
|
"MetricSchema",
|
|
35
37
|
"PDKSchema",
|
siliconcompiler/_metadata.py
CHANGED
siliconcompiler/apps/sc_issue.py
CHANGED
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
import siliconcompiler
|
|
5
5
|
import tarfile
|
|
6
6
|
import json
|
|
7
|
-
from siliconcompiler.scheduler import
|
|
7
|
+
from siliconcompiler.scheduler.schedulernode import SchedulerNode
|
|
8
8
|
from siliconcompiler.utils.issue import generate_testcase
|
|
9
9
|
from siliconcompiler.tools._common import get_tool_task
|
|
10
10
|
|
|
@@ -153,8 +153,10 @@ To run a testcase, use:
|
|
|
153
153
|
# Run task
|
|
154
154
|
# Rerun setup task, assumed to be running in its own thread so
|
|
155
155
|
# multiprocess is not needed
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
SchedulerNode(chip,
|
|
157
|
+
step,
|
|
158
|
+
index,
|
|
159
|
+
replay=True).run()
|
|
158
160
|
|
|
159
161
|
return 0
|
|
160
162
|
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
# Copyright 2023 Silicon Compiler Authors. All Rights Reserved.
|
|
2
|
-
import os
|
|
3
2
|
import sys
|
|
4
3
|
|
|
5
4
|
from siliconcompiler import Chip
|
|
6
5
|
from siliconcompiler import SiliconCompilerError
|
|
7
6
|
from siliconcompiler.remote.client import Client, ConfigureClient
|
|
8
|
-
from siliconcompiler.scheduler import _finalize_run
|
|
9
|
-
from siliconcompiler.flowgraph import RuntimeFlowgraph
|
|
10
7
|
|
|
11
8
|
|
|
12
9
|
def main():
|
|
@@ -169,20 +166,6 @@ To delete a job, use:
|
|
|
169
166
|
chip.logger.error(f'{e}')
|
|
170
167
|
return 1
|
|
171
168
|
|
|
172
|
-
# Wrap up run
|
|
173
|
-
runtime = RuntimeFlowgraph(
|
|
174
|
-
chip.schema.get("flowgraph", flow, field='schema'),
|
|
175
|
-
from_steps=chip.get('option', 'from'),
|
|
176
|
-
to_steps=chip.get('option', 'to'),
|
|
177
|
-
prune_nodes=chip.get('option', 'prune'))
|
|
178
|
-
for step, index in runtime.get_nodes():
|
|
179
|
-
manifest = os.path.join(chip.getworkdir(step=step, index=index),
|
|
180
|
-
'outputs',
|
|
181
|
-
f'{chip.design}.pkg.json')
|
|
182
|
-
if os.path.exists(manifest):
|
|
183
|
-
chip.schema.read_journal(manifest)
|
|
184
|
-
_finalize_run(chip)
|
|
185
|
-
|
|
186
169
|
# Summarize the run.
|
|
187
170
|
chip.summary()
|
|
188
171
|
|
siliconcompiler/checklist.py
CHANGED
siliconcompiler/core.py
CHANGED
|
@@ -18,9 +18,9 @@ import csv
|
|
|
18
18
|
import yaml
|
|
19
19
|
from inspect import getfullargspec
|
|
20
20
|
from siliconcompiler import Schema
|
|
21
|
-
from siliconcompiler.schema import SCHEMA_VERSION, PerNode,
|
|
21
|
+
from siliconcompiler.schema import SCHEMA_VERSION, PerNode, Journal, EditableSchema
|
|
22
22
|
from siliconcompiler.schema.parametertype import NodeType
|
|
23
|
-
from siliconcompiler.schema.parametervalue import FileNodeValue
|
|
23
|
+
from siliconcompiler.schema.parametervalue import FileNodeValue
|
|
24
24
|
from siliconcompiler.schema import utils as schema_utils
|
|
25
25
|
from siliconcompiler import utils
|
|
26
26
|
from siliconcompiler.utils.logging import SCColorLoggerFormatter, \
|
|
@@ -34,9 +34,8 @@ from siliconcompiler.report import _generate_summary_image, _open_summary_image
|
|
|
34
34
|
from siliconcompiler.report.dashboard.web import WebDashboard
|
|
35
35
|
from siliconcompiler.report.dashboard.cli import CliDashboard
|
|
36
36
|
from siliconcompiler.report.dashboard import DashboardType
|
|
37
|
-
from siliconcompiler import package as sc_package
|
|
38
37
|
import glob
|
|
39
|
-
from siliconcompiler.scheduler import
|
|
38
|
+
from siliconcompiler.scheduler.scheduler import Scheduler
|
|
40
39
|
from siliconcompiler.utils.flowgraph import _check_flowgraph_io, _get_flowgraph_information
|
|
41
40
|
from siliconcompiler.tools._common import get_tool_task
|
|
42
41
|
from types import FunctionType, ModuleType
|
|
@@ -1102,7 +1101,8 @@ class Chip:
|
|
|
1102
1101
|
'''
|
|
1103
1102
|
|
|
1104
1103
|
if package:
|
|
1105
|
-
|
|
1104
|
+
resolvers = self.get("package", field="schema").get_resolvers()
|
|
1105
|
+
filename = os.path.join(resolvers[package](), filename)
|
|
1106
1106
|
|
|
1107
1107
|
if not os.path.isfile(filename):
|
|
1108
1108
|
raise FileNotFoundError(filename)
|
|
@@ -1110,10 +1110,16 @@ class Chip:
|
|
|
1110
1110
|
package_name = f'flist-{os.path.basename(filename)}'
|
|
1111
1111
|
package_dir = os.path.dirname(os.path.abspath(filename))
|
|
1112
1112
|
|
|
1113
|
-
env_vars = utils.get_env_vars(self, None, None)
|
|
1114
|
-
|
|
1115
1113
|
def __make_path(rel, path):
|
|
1116
|
-
|
|
1114
|
+
env_save = os.environ.copy()
|
|
1115
|
+
schema_env = {}
|
|
1116
|
+
for env in self.getkeys('option', 'env'):
|
|
1117
|
+
schema_env[env] = self.get('option', 'env', env)
|
|
1118
|
+
os.environ.update(schema_env)
|
|
1119
|
+
path = os.path.expandvars(path)
|
|
1120
|
+
path = os.path.expanduser(path)
|
|
1121
|
+
os.environ.clear()
|
|
1122
|
+
os.environ.update(env_save)
|
|
1117
1123
|
if os.path.isabs(path):
|
|
1118
1124
|
if path.startswith(rel):
|
|
1119
1125
|
return os.path.relpath(path, rel), package_name
|
|
@@ -1380,18 +1386,17 @@ class Chip:
|
|
|
1380
1386
|
else:
|
|
1381
1387
|
search_paths = [self.cwd]
|
|
1382
1388
|
|
|
1383
|
-
|
|
1389
|
+
resolvers = self.get("package", field="schema").get_resolvers()
|
|
1384
1390
|
for (dependency, path) in zip(dependencies, paths):
|
|
1385
1391
|
faux_param = FileNodeValue()
|
|
1386
1392
|
faux_param.set(path)
|
|
1387
1393
|
try:
|
|
1388
1394
|
if dependency:
|
|
1389
1395
|
faux_param.set(dependency, field='package')
|
|
1390
|
-
faux_search = [
|
|
1396
|
+
faux_search = [resolvers[dependency]()]
|
|
1391
1397
|
else:
|
|
1392
1398
|
faux_search = search_paths
|
|
1393
1399
|
resolved = faux_param.resolve_path(
|
|
1394
|
-
envvars=env_vars,
|
|
1395
1400
|
search=faux_search,
|
|
1396
1401
|
collection_dir=collection_dir)
|
|
1397
1402
|
except FileNotFoundError:
|
|
@@ -1547,39 +1552,19 @@ class Chip:
|
|
|
1547
1552
|
True if all file paths are valid, otherwise False.
|
|
1548
1553
|
'''
|
|
1549
1554
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
is_file = 'file' in paramtype
|
|
1555
|
-
is_dir = 'dir' in paramtype
|
|
1556
|
-
is_list = paramtype.startswith('[')
|
|
1557
|
-
|
|
1558
|
-
if is_file or is_dir:
|
|
1559
|
-
if keypath[-2:] == ('option', 'builddir'):
|
|
1560
|
-
# Skip ['option', 'builddir'] since it will get created by run() if it doesn't
|
|
1561
|
-
# exist
|
|
1562
|
-
continue
|
|
1563
|
-
|
|
1564
|
-
for check_files, step, index in self.schema.get(*keypath, field=None).getvalues():
|
|
1565
|
-
if not check_files:
|
|
1566
|
-
continue
|
|
1555
|
+
ignore_keys = []
|
|
1556
|
+
for keypath in self.allkeys():
|
|
1557
|
+
if keypath[-2:] == ('option', 'builddir'):
|
|
1558
|
+
ignore_keys.append(keypath)
|
|
1567
1559
|
|
|
1568
|
-
|
|
1569
|
-
check_files = [check_files]
|
|
1570
|
-
|
|
1571
|
-
for idx, check_file in enumerate(check_files):
|
|
1572
|
-
found_file = self.__find_files(*keypath,
|
|
1573
|
-
missing_ok=True,
|
|
1574
|
-
step=step, index=index,
|
|
1575
|
-
list_index=idx)
|
|
1576
|
-
if is_list:
|
|
1577
|
-
found_file = found_file[0]
|
|
1578
|
-
if not found_file:
|
|
1579
|
-
self.logger.error(f"Parameter {keypath} path {check_file} is invalid")
|
|
1580
|
-
error = True
|
|
1560
|
+
package_map = self.get("package", field="schema").get_resolvers()
|
|
1581
1561
|
|
|
1582
|
-
return
|
|
1562
|
+
return self.schema.check_filepaths(
|
|
1563
|
+
ignore_keys=ignore_keys,
|
|
1564
|
+
logger=self.logger,
|
|
1565
|
+
packages=package_map,
|
|
1566
|
+
collection_dir=self._getcollectdir(),
|
|
1567
|
+
cwd=self.cwd)
|
|
1583
1568
|
|
|
1584
1569
|
###########################################################################
|
|
1585
1570
|
def check_manifest(self):
|
|
@@ -1796,10 +1781,7 @@ class Chip:
|
|
|
1796
1781
|
schema.write_manifest(filepath)
|
|
1797
1782
|
return
|
|
1798
1783
|
|
|
1799
|
-
tcl_record =
|
|
1800
|
-
if isinstance(schema, JournalingSchema):
|
|
1801
|
-
tcl_record = "get" in schema.get_journaling_types()
|
|
1802
|
-
schema = schema.get_base_schema()
|
|
1784
|
+
tcl_record = "get" in Journal.access(schema).get_types()
|
|
1803
1785
|
|
|
1804
1786
|
is_csv = re.search(r'(\.csv)(\.gz)*$', filepath)
|
|
1805
1787
|
|
|
@@ -3201,9 +3183,14 @@ class Chip:
|
|
|
3201
3183
|
>>> run()
|
|
3202
3184
|
Runs the execution flow defined by the flowgraph dictionary.
|
|
3203
3185
|
'''
|
|
3186
|
+
from siliconcompiler.remote.client import ClientScheduler
|
|
3204
3187
|
|
|
3205
3188
|
try:
|
|
3206
|
-
|
|
3189
|
+
if self.get('option', 'remote'):
|
|
3190
|
+
scheduler = ClientScheduler(self)
|
|
3191
|
+
else:
|
|
3192
|
+
scheduler = Scheduler(self)
|
|
3193
|
+
scheduler.run()
|
|
3207
3194
|
except Exception as e:
|
|
3208
3195
|
if raise_exception:
|
|
3209
3196
|
raise e
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
|
|
3
|
+
from siliconcompiler.schema.baseschema import BaseSchema
|
|
4
|
+
from siliconcompiler.schema.editableschema import EditableSchema
|
|
5
|
+
from siliconcompiler.schema.parameter import Parameter, Scope
|
|
6
|
+
from siliconcompiler.schema.namedschema import NamedSchema
|
|
7
|
+
from siliconcompiler.schema.utils import trim
|
|
8
|
+
|
|
9
|
+
from siliconcompiler.package import Resolver
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DependencySchema(BaseSchema):
|
|
13
|
+
'''
|
|
14
|
+
Schema extension to add :meth:`.add_dep` capability to a schema section.
|
|
15
|
+
'''
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
self.__deps = {}
|
|
21
|
+
|
|
22
|
+
schema = EditableSchema(self)
|
|
23
|
+
schema.insert(
|
|
24
|
+
"deps",
|
|
25
|
+
Parameter(
|
|
26
|
+
'[str]',
|
|
27
|
+
scope=Scope.GLOBAL,
|
|
28
|
+
lock=True,
|
|
29
|
+
shorthelp="List of dependencies",
|
|
30
|
+
help="List of named object dependencies included via add_dep()."))
|
|
31
|
+
|
|
32
|
+
schema.insert(
|
|
33
|
+
'package', 'default', 'root',
|
|
34
|
+
Parameter(
|
|
35
|
+
'str',
|
|
36
|
+
scope=Scope.GLOBAL,
|
|
37
|
+
shorthelp="Package: package root",
|
|
38
|
+
example=[
|
|
39
|
+
"api: chip.set('source', "
|
|
40
|
+
"'freepdk45_data', 'path', 'ssh://git@github.com/siliconcompiler/freepdk45/')"],
|
|
41
|
+
help=trim("""
|
|
42
|
+
Package root path, this points the location where the package data can be
|
|
43
|
+
retrieved or accessed.
|
|
44
|
+
Allowed roots:
|
|
45
|
+
|
|
46
|
+
* /path/on/network/drive
|
|
47
|
+
* file:///path/on/network/drive
|
|
48
|
+
* git+https://github.com/xyz/xyz
|
|
49
|
+
* git://github.com/xyz/xyz
|
|
50
|
+
* git+ssh://github.com/xyz/xyz
|
|
51
|
+
* ssh://github.com/xyz/xyz
|
|
52
|
+
* https://github.com/xyz/xyz/archive
|
|
53
|
+
* https://zeroasic.com/xyz.tar.gz
|
|
54
|
+
* github://siliconcompiler/lambdapdk/v1.0/asap7.tar.gz
|
|
55
|
+
* python://siliconcompiler
|
|
56
|
+
""")))
|
|
57
|
+
|
|
58
|
+
schema.insert(
|
|
59
|
+
'package', 'default', 'tag',
|
|
60
|
+
Parameter(
|
|
61
|
+
'str',
|
|
62
|
+
scope=Scope.GLOBAL,
|
|
63
|
+
shorthelp="Package: package tag/version",
|
|
64
|
+
example=[
|
|
65
|
+
"api: chip.set('source', 'freepdk45_data', 'ref', '07ec4aa')"],
|
|
66
|
+
help=trim("""
|
|
67
|
+
Package reference tag. The meaning of the this tag depends on the context of
|
|
68
|
+
the root.
|
|
69
|
+
For git, this can be a tag, branch, or commit id. For https this is the version
|
|
70
|
+
of the file that will be downloaded.
|
|
71
|
+
""")))
|
|
72
|
+
|
|
73
|
+
def _from_dict(self, manifest, keypath, version=None):
|
|
74
|
+
self.set("deps", False, field="lock")
|
|
75
|
+
ret = super()._from_dict(manifest, keypath, version)
|
|
76
|
+
self.set("deps", True, field="lock")
|
|
77
|
+
return ret
|
|
78
|
+
|
|
79
|
+
def add_dep(self, obj: NamedSchema, clobber: bool = True) -> bool:
|
|
80
|
+
"""
|
|
81
|
+
Adds a module to this object.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
obj (:class:`NamedSchema`): Module to add
|
|
85
|
+
clobber (bool): If true will insert the object and overwrite any
|
|
86
|
+
existing with the same name
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
True if object was imported, otherwise false.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
if not isinstance(obj, NamedSchema):
|
|
93
|
+
raise TypeError(f"Cannot add an object of type: {type(obj)}")
|
|
94
|
+
|
|
95
|
+
if not clobber and obj.name() in self.__deps:
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
if obj.name() not in self.__deps:
|
|
99
|
+
self.set("deps", False, field="lock")
|
|
100
|
+
self.add("deps", obj.name())
|
|
101
|
+
self.set("deps", True, field="lock")
|
|
102
|
+
|
|
103
|
+
self.__deps[obj.name()] = obj
|
|
104
|
+
obj._reset()
|
|
105
|
+
|
|
106
|
+
return True
|
|
107
|
+
|
|
108
|
+
def write_depgraph(self, filename: str,
|
|
109
|
+
fontcolor: str = '#000000',
|
|
110
|
+
background: str = 'transparent',
|
|
111
|
+
fontsize: str = '14',
|
|
112
|
+
border: bool = True, landscape: bool = False) -> None:
|
|
113
|
+
r'''
|
|
114
|
+
Renders and saves the dependency graph to a file.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
filename (filepath): Output filepath
|
|
118
|
+
fontcolor (str): Node font RGB color hex value
|
|
119
|
+
background (str): Background color
|
|
120
|
+
fontsize (str): Node text font size
|
|
121
|
+
border (bool): Enables node border if True
|
|
122
|
+
landscape (bool): Renders graph in landscape layout if True
|
|
123
|
+
|
|
124
|
+
Examples:
|
|
125
|
+
>>> schema.write_depgraph('mydump.png')
|
|
126
|
+
Renders the object dependency graph and writes the result to a png file.
|
|
127
|
+
'''
|
|
128
|
+
import graphviz
|
|
129
|
+
|
|
130
|
+
filepath = os.path.abspath(filename)
|
|
131
|
+
fileroot, ext = os.path.splitext(filepath)
|
|
132
|
+
fileformat = ext[1:]
|
|
133
|
+
|
|
134
|
+
# controlling border width
|
|
135
|
+
if border:
|
|
136
|
+
penwidth = '1'
|
|
137
|
+
else:
|
|
138
|
+
penwidth = '0'
|
|
139
|
+
|
|
140
|
+
# controlling graph direction
|
|
141
|
+
if landscape:
|
|
142
|
+
rankdir = 'LR'
|
|
143
|
+
else:
|
|
144
|
+
rankdir = 'TB'
|
|
145
|
+
|
|
146
|
+
dot = graphviz.Digraph(format=fileformat)
|
|
147
|
+
dot.graph_attr['rankdir'] = rankdir
|
|
148
|
+
dot.attr(bgcolor=background)
|
|
149
|
+
|
|
150
|
+
def make_label(dep):
|
|
151
|
+
return f"lib-{dep.name()}"
|
|
152
|
+
|
|
153
|
+
nodes = {
|
|
154
|
+
self.name(): {
|
|
155
|
+
"text": self.name(),
|
|
156
|
+
"shape": "box",
|
|
157
|
+
"color": background,
|
|
158
|
+
"connects_to": set([make_label(subdep) for subdep in self.__deps.values()])
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
for dep in self.get_dep():
|
|
162
|
+
nodes[make_label(dep)] = {
|
|
163
|
+
"text": dep.name(),
|
|
164
|
+
"shape": "oval",
|
|
165
|
+
"color": background,
|
|
166
|
+
"connects_to": set([make_label(subdep) for subdep in dep.__deps.values()])
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for label, info in nodes.items():
|
|
170
|
+
dot.node(label, label=info['text'], bordercolor=fontcolor, style='filled',
|
|
171
|
+
fontcolor=fontcolor, fontsize=fontsize, ordering="in",
|
|
172
|
+
penwidth=penwidth, fillcolor=info["color"], shape=info['shape'])
|
|
173
|
+
|
|
174
|
+
for conn in info['connects_to']:
|
|
175
|
+
dot.edge(label, conn, dir='back')
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
dot.render(filename=fileroot, cleanup=True)
|
|
179
|
+
except graphviz.ExecutableNotFound as e:
|
|
180
|
+
raise RuntimeError(f'Unable to save flowgraph: {e}')
|
|
181
|
+
|
|
182
|
+
def __get_all_deps(self, seen: set) -> list:
|
|
183
|
+
'''
|
|
184
|
+
Loop through the dependency tree and generate a flat list
|
|
185
|
+
'''
|
|
186
|
+
deps = []
|
|
187
|
+
|
|
188
|
+
for obj in self.__deps.values():
|
|
189
|
+
if obj.name() in seen:
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
deps.append(obj)
|
|
193
|
+
seen.add(obj.name())
|
|
194
|
+
|
|
195
|
+
if not isinstance(obj, DependencySchema):
|
|
196
|
+
# nothing to iterate over
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
for obj_dep in obj.__get_all_deps(seen):
|
|
200
|
+
deps.append(obj_dep)
|
|
201
|
+
seen.add(obj_dep.name())
|
|
202
|
+
|
|
203
|
+
return deps
|
|
204
|
+
|
|
205
|
+
def get_dep(self, name: str = None, hierarchy: bool = True) -> list:
|
|
206
|
+
'''
|
|
207
|
+
Returns all dependencies associated with this object or a specific one if requested.
|
|
208
|
+
|
|
209
|
+
Raises:
|
|
210
|
+
KeyError: if the module specific module is requested but not found
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
name (str): name of the module
|
|
214
|
+
hierarchy (bool): if True, will return all modules including children
|
|
215
|
+
otherwise only this objects modules are returned.
|
|
216
|
+
'''
|
|
217
|
+
|
|
218
|
+
if name:
|
|
219
|
+
if name not in self.__deps:
|
|
220
|
+
raise KeyError(f"{name} is not an imported module")
|
|
221
|
+
|
|
222
|
+
return self.__deps[name]
|
|
223
|
+
|
|
224
|
+
if hierarchy:
|
|
225
|
+
return self.__get_all_deps(set())
|
|
226
|
+
return list(self.__deps.values())
|
|
227
|
+
|
|
228
|
+
def remove_dep(self, name: str) -> bool:
|
|
229
|
+
'''
|
|
230
|
+
Removes a previously registered module.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
name (str): name of the module
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
True if the module was removed, False is not found.
|
|
237
|
+
'''
|
|
238
|
+
if name not in self.__deps:
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
del self.__deps[name]
|
|
242
|
+
|
|
243
|
+
# Remove from dependency list
|
|
244
|
+
dependencies = self.get("deps")
|
|
245
|
+
dependencies.remove(name)
|
|
246
|
+
|
|
247
|
+
self.set("deps", False, field="lock")
|
|
248
|
+
self.set("deps", dependencies)
|
|
249
|
+
self.set("deps", True, field="lock")
|
|
250
|
+
|
|
251
|
+
return True
|
|
252
|
+
|
|
253
|
+
def _populate_deps(self, module_map: dict):
|
|
254
|
+
if self.__deps:
|
|
255
|
+
return
|
|
256
|
+
|
|
257
|
+
for module in self.get("deps"):
|
|
258
|
+
if module not in module_map:
|
|
259
|
+
raise ValueError(f"{module} not available in map")
|
|
260
|
+
self.__deps[module] = module_map[module]
|
|
261
|
+
|
|
262
|
+
if isinstance(self.__deps[module], DependencySchema):
|
|
263
|
+
self.__deps[module]._populate_deps(module_map)
|
|
264
|
+
|
|
265
|
+
def register_package(self, name: str, root: str, tag: str = None):
|
|
266
|
+
"""
|
|
267
|
+
Registers a package by its name with the root and associated tag.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
name (str): Package name
|
|
271
|
+
root (str): Path to the root, can be directory, git url, or archive url
|
|
272
|
+
tag (str): Reference of the sources, can be commitid, branch name, tag
|
|
273
|
+
|
|
274
|
+
Examples:
|
|
275
|
+
>>> schema.register_package('siliconcompiler_data',
|
|
276
|
+
'git+https://github.com/siliconcompiler/siliconcompiler',
|
|
277
|
+
'v1.0.0')
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
if os.path.isfile(root):
|
|
281
|
+
root = os.path.dirname(os.path.abspath(root))
|
|
282
|
+
|
|
283
|
+
self.set("package", name, "root", root)
|
|
284
|
+
if tag:
|
|
285
|
+
self.set("package", name, "tag", tag)
|
|
286
|
+
|
|
287
|
+
def find_package(self, name: str):
|
|
288
|
+
"""
|
|
289
|
+
Returns absolute path to the package root.
|
|
290
|
+
|
|
291
|
+
Raises:
|
|
292
|
+
ValueError: is package is not found
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
name (str): name of the package to find.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
Path to the package directory root.
|
|
299
|
+
|
|
300
|
+
Examples:
|
|
301
|
+
>>> schema.find_package('siliconcompiler')
|
|
302
|
+
Returns the path to the root of the siliconcompiler package.
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
if not self.valid("package", name):
|
|
306
|
+
raise ValueError(f"{name} is not a recognized source")
|
|
307
|
+
|
|
308
|
+
root = self.get("package", name, "root")
|
|
309
|
+
tag = self.get("package", name, "tag")
|
|
310
|
+
|
|
311
|
+
resolver = Resolver.find_resolver(root)
|
|
312
|
+
return resolver(name, self._parent(root=True), root, tag).get_path()
|
|
313
|
+
|
|
314
|
+
def __get_resolver_map(self):
|
|
315
|
+
"""
|
|
316
|
+
Generate the resolver map got package handling for find_files and check_filepaths
|
|
317
|
+
"""
|
|
318
|
+
schema_root = self._parent(root=True)
|
|
319
|
+
resolver_map = {}
|
|
320
|
+
for package in self.getkeys("package"):
|
|
321
|
+
root = self.get("package", package, "root")
|
|
322
|
+
tag = self.get("package", package, "tag")
|
|
323
|
+
resolver = Resolver.find_resolver(root)
|
|
324
|
+
resolver_map[package] = resolver(package, schema_root, root, tag).get_path
|
|
325
|
+
return resolver_map
|
|
326
|
+
|
|
327
|
+
def find_files(self, *keypath,
|
|
328
|
+
missing_ok=False,
|
|
329
|
+
step=None, index=None):
|
|
330
|
+
"""
|
|
331
|
+
Returns absolute paths to files or directories based on the keypath
|
|
332
|
+
provided.
|
|
333
|
+
|
|
334
|
+
The keypath provided must point to a schema parameter of type file, dir,
|
|
335
|
+
or lists of either. Otherwise, it will trigger an error.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
keypath (list of str): Variable length schema key list.
|
|
339
|
+
missing_ok (bool): If True, silently return None when files aren't
|
|
340
|
+
found. If False, print an error and set the error flag.
|
|
341
|
+
step (str): Step name to access for parameters that may be specified
|
|
342
|
+
on a per-node basis.
|
|
343
|
+
index (str): Index name to access for parameters that may be specified
|
|
344
|
+
on a per-node basis.
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
If keys points to a scalar entry, returns an absolute path to that
|
|
348
|
+
file/directory, or None if not found. It keys points to a list
|
|
349
|
+
entry, returns a list of either the absolute paths or None for each
|
|
350
|
+
entry, depending on whether it is found.
|
|
351
|
+
|
|
352
|
+
Examples:
|
|
353
|
+
>>> schema.find_files('input', 'verilog')
|
|
354
|
+
Returns a list of absolute paths to source files, as specified in
|
|
355
|
+
the schema.
|
|
356
|
+
"""
|
|
357
|
+
schema_root = self._parent(root=True)
|
|
358
|
+
cwd = getattr(schema_root, "cwd", os.getcwd())
|
|
359
|
+
collection_dir = getattr(schema_root, "collection_dir", None)
|
|
360
|
+
if collection_dir:
|
|
361
|
+
collection_dir = collection_dir()
|
|
362
|
+
|
|
363
|
+
return super().find_files(*keypath,
|
|
364
|
+
missing_ok=missing_ok,
|
|
365
|
+
step=step, index=index,
|
|
366
|
+
packages=self.__get_resolver_map(),
|
|
367
|
+
collection_dir=collection_dir,
|
|
368
|
+
cwd=cwd)
|
|
369
|
+
|
|
370
|
+
def check_filepaths(self, ignore_keys=None):
|
|
371
|
+
'''
|
|
372
|
+
Verifies that paths to all files in manifest are valid.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
ignore_keys (list of keypaths): list of keypaths to ignore while checking
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
True if all file paths are valid, otherwise False.
|
|
379
|
+
'''
|
|
380
|
+
schema_root = self._parent(root=True)
|
|
381
|
+
cwd = getattr(schema_root, "cwd", os.getcwd())
|
|
382
|
+
logger = getattr(schema_root, "logger", None)
|
|
383
|
+
collection_dir = getattr(schema_root, "collection_dir", None)
|
|
384
|
+
if collection_dir:
|
|
385
|
+
collection_dir = collection_dir()
|
|
386
|
+
|
|
387
|
+
return super().check_filepaths(
|
|
388
|
+
ignore_keys=ignore_keys,
|
|
389
|
+
logger=logger,
|
|
390
|
+
packages=self.__get_resolver_map(),
|
|
391
|
+
collection_dir=collection_dir,
|
|
392
|
+
cwd=cwd)
|