siliconcompiler 0.35.0__py3-none-any.whl → 0.35.1__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/_metadata.py +1 -1
- siliconcompiler/apps/_common.py +3 -2
- siliconcompiler/apps/sc_dashboard.py +3 -1
- siliconcompiler/apps/sc_install.py +149 -37
- siliconcompiler/apps/smake.py +9 -3
- siliconcompiler/checklist.py +3 -3
- siliconcompiler/data/demo_fpga/z1000_yosys_config.json +24 -0
- siliconcompiler/design.py +51 -45
- siliconcompiler/flowgraph.py +2 -2
- siliconcompiler/library.py +23 -12
- siliconcompiler/package/__init__.py +77 -49
- siliconcompiler/package/git.py +11 -6
- siliconcompiler/package/github.py +11 -6
- siliconcompiler/package/https.py +6 -4
- siliconcompiler/pdk.py +23 -16
- siliconcompiler/scheduler/scheduler.py +30 -22
- siliconcompiler/scheduler/schedulernode.py +60 -50
- siliconcompiler/scheduler/taskscheduler.py +52 -32
- siliconcompiler/schema/baseschema.py +88 -69
- siliconcompiler/schema/docs/schemagen.py +4 -3
- siliconcompiler/schema/editableschema.py +5 -5
- siliconcompiler/schema/journal.py +19 -13
- siliconcompiler/schema/namedschema.py +16 -10
- siliconcompiler/schema/parameter.py +64 -37
- siliconcompiler/schema/parametervalue.py +126 -80
- siliconcompiler/schema/safeschema.py +16 -7
- siliconcompiler/schema/utils.py +3 -1
- siliconcompiler/schema_support/cmdlineschema.py +9 -9
- siliconcompiler/schema_support/dependencyschema.py +12 -7
- siliconcompiler/schema_support/filesetschema.py +15 -10
- siliconcompiler/schema_support/metric.py +29 -17
- siliconcompiler/schema_support/packageschema.py +2 -2
- siliconcompiler/schema_support/pathschema.py +30 -18
- siliconcompiler/schema_support/record.py +30 -23
- siliconcompiler/tool.py +265 -210
- siliconcompiler/tools/opensta/timing.py +13 -0
- siliconcompiler/tools/yosys/syn_fpga.py +3 -2
- siliconcompiler/toolscripts/_tools.json +3 -3
- siliconcompiler/utils/__init__.py +23 -16
- siliconcompiler/utils/curation.py +11 -5
- siliconcompiler/utils/multiprocessing.py +16 -14
- siliconcompiler/utils/paths.py +24 -12
- siliconcompiler/utils/units.py +16 -12
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/METADATA +3 -4
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/RECORD +49 -48
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/entry_points.txt +4 -3
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,8 @@ import traceback
|
|
|
8
8
|
|
|
9
9
|
import os.path
|
|
10
10
|
|
|
11
|
+
from typing import Union, TYPE_CHECKING
|
|
12
|
+
|
|
11
13
|
from siliconcompiler import NodeStatus
|
|
12
14
|
from siliconcompiler.schema import Journal
|
|
13
15
|
from siliconcompiler.flowgraph import RuntimeFlowgraph
|
|
@@ -23,6 +25,12 @@ from siliconcompiler.utils.multiprocessing import MPManager
|
|
|
23
25
|
from siliconcompiler.scheduler import send_messages, SCRuntimeError
|
|
24
26
|
from siliconcompiler.utils.paths import collectiondir, jobdir, workdir
|
|
25
27
|
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from siliconcompiler.project import Project
|
|
30
|
+
from siliconcompiler import Flowgraph
|
|
31
|
+
from siliconcompiler.schema_support.record import RecordSchema
|
|
32
|
+
from siliconcompiler.schema_support.metric import MetricSchema
|
|
33
|
+
|
|
26
34
|
|
|
27
35
|
class Scheduler:
|
|
28
36
|
"""
|
|
@@ -37,7 +45,7 @@ class Scheduler:
|
|
|
37
45
|
and reporting results.
|
|
38
46
|
"""
|
|
39
47
|
|
|
40
|
-
def __init__(self, project):
|
|
48
|
+
def __init__(self, project: "Project"):
|
|
41
49
|
"""
|
|
42
50
|
Initializes the Scheduler.
|
|
43
51
|
|
|
@@ -58,7 +66,7 @@ class Scheduler:
|
|
|
58
66
|
if flow not in self.__project.getkeys("flowgraph"):
|
|
59
67
|
raise SCRuntimeError("flow is not defined")
|
|
60
68
|
|
|
61
|
-
self.__flow = self.__project.get("flowgraph", flow, field="schema")
|
|
69
|
+
self.__flow: "Flowgraph" = self.__project.get("flowgraph", flow, field="schema")
|
|
62
70
|
from_steps = self.__project.get('option', 'from')
|
|
63
71
|
to_steps = self.__project.get('option', 'to')
|
|
64
72
|
prune_nodes = self.__project.get('option', 'prune')
|
|
@@ -77,15 +85,15 @@ class Scheduler:
|
|
|
77
85
|
self.__flow,
|
|
78
86
|
from_steps=from_steps,
|
|
79
87
|
to_steps=to_steps,
|
|
80
|
-
prune_nodes=
|
|
88
|
+
prune_nodes=prune_nodes)
|
|
81
89
|
|
|
82
90
|
self.__flow_load_runtime = RuntimeFlowgraph(
|
|
83
91
|
self.__flow,
|
|
84
92
|
to_steps=from_steps,
|
|
85
93
|
prune_nodes=prune_nodes)
|
|
86
94
|
|
|
87
|
-
self.__record = self.__project.get("record", field="schema")
|
|
88
|
-
self.__metrics = self.__project.get("metric", field="schema")
|
|
95
|
+
self.__record: "RecordSchema" = self.__project.get("record", field="schema")
|
|
96
|
+
self.__metrics: "MetricSchema" = self.__project.get("metric", field="schema")
|
|
89
97
|
|
|
90
98
|
self.__tasks = {}
|
|
91
99
|
|
|
@@ -95,14 +103,14 @@ class Scheduler:
|
|
|
95
103
|
self.__logfile = None
|
|
96
104
|
|
|
97
105
|
@property
|
|
98
|
-
def log(self) -> str:
|
|
106
|
+
def log(self) -> Union[None, str]:
|
|
99
107
|
"""
|
|
100
108
|
Returns path to the running job log
|
|
101
109
|
"""
|
|
102
110
|
return self.__logfile
|
|
103
111
|
|
|
104
112
|
@property
|
|
105
|
-
def project(self):
|
|
113
|
+
def project(self) -> "Project":
|
|
106
114
|
"""
|
|
107
115
|
Returns the Project object associated with this scheduler.
|
|
108
116
|
|
|
@@ -114,7 +122,7 @@ class Scheduler:
|
|
|
114
122
|
"""
|
|
115
123
|
return self.__project
|
|
116
124
|
|
|
117
|
-
def __print_status(self, header):
|
|
125
|
+
def __print_status(self, header: str) -> None:
|
|
118
126
|
"""
|
|
119
127
|
Private helper to print the current status of all nodes for debugging.
|
|
120
128
|
|
|
@@ -127,7 +135,7 @@ class Scheduler:
|
|
|
127
135
|
f"{self.__record.get('status', step=step, index=index)}")
|
|
128
136
|
self.__logger.debug("####")
|
|
129
137
|
|
|
130
|
-
def check_manifest(self):
|
|
138
|
+
def check_manifest(self) -> bool:
|
|
131
139
|
"""
|
|
132
140
|
Checks the validity of the Project's manifest before a run.
|
|
133
141
|
|
|
@@ -137,7 +145,7 @@ class Scheduler:
|
|
|
137
145
|
self.__logger.info("Checking manifest before running.")
|
|
138
146
|
return self.__project.check_manifest()
|
|
139
147
|
|
|
140
|
-
def run_core(self):
|
|
148
|
+
def run_core(self) -> None:
|
|
141
149
|
"""
|
|
142
150
|
Executes the core task scheduling loop.
|
|
143
151
|
|
|
@@ -191,7 +199,7 @@ class Scheduler:
|
|
|
191
199
|
# Mark error to keep logfile
|
|
192
200
|
MPManager.error("uncaught exception")
|
|
193
201
|
|
|
194
|
-
def __install_file_logger(self):
|
|
202
|
+
def __install_file_logger(self) -> None:
|
|
195
203
|
"""
|
|
196
204
|
Set up a per-job file logger for the current project and attach it to the
|
|
197
205
|
scheduler's logger.
|
|
@@ -215,7 +223,7 @@ class Scheduler:
|
|
|
215
223
|
self.__joblog_handler.setFormatter(SCLoggerFormatter())
|
|
216
224
|
self.__logger.addHandler(self.__joblog_handler)
|
|
217
225
|
|
|
218
|
-
def run(self):
|
|
226
|
+
def run(self) -> None:
|
|
219
227
|
"""
|
|
220
228
|
The main entry point to start the compilation flow.
|
|
221
229
|
|
|
@@ -282,7 +290,7 @@ class Scheduler:
|
|
|
282
290
|
# Restore hook
|
|
283
291
|
sys.excepthook = org_excepthook
|
|
284
292
|
|
|
285
|
-
def __check_tool_requirements(self):
|
|
293
|
+
def __check_tool_requirements(self) -> bool:
|
|
286
294
|
"""
|
|
287
295
|
Performs pre-run validation checks.
|
|
288
296
|
|
|
@@ -343,7 +351,7 @@ class Scheduler:
|
|
|
343
351
|
|
|
344
352
|
return not error
|
|
345
353
|
|
|
346
|
-
def __check_flowgraph_io(self):
|
|
354
|
+
def __check_flowgraph_io(self) -> bool:
|
|
347
355
|
"""
|
|
348
356
|
Validate that every runtime node will receive its required input files and that no
|
|
349
357
|
input file is provided by more than one source.
|
|
@@ -415,7 +423,7 @@ class Scheduler:
|
|
|
415
423
|
|
|
416
424
|
return not error
|
|
417
425
|
|
|
418
|
-
def __mark_pending(self, step, index):
|
|
426
|
+
def __mark_pending(self, step: str, index: str) -> None:
|
|
419
427
|
"""
|
|
420
428
|
Private helper to recursively mark a node and its dependents as PENDING.
|
|
421
429
|
|
|
@@ -438,7 +446,7 @@ class Scheduler:
|
|
|
438
446
|
# Mark following steps as pending
|
|
439
447
|
self.__record.set('status', NodeStatus.PENDING, step=next_step, index=next_index)
|
|
440
448
|
|
|
441
|
-
def __run_setup(self):
|
|
449
|
+
def __run_setup(self) -> None:
|
|
442
450
|
"""
|
|
443
451
|
Private helper to perform initial setup for the entire run.
|
|
444
452
|
|
|
@@ -481,7 +489,7 @@ class Scheduler:
|
|
|
481
489
|
|
|
482
490
|
self.__reset_flow_nodes()
|
|
483
491
|
|
|
484
|
-
def __reset_flow_nodes(self):
|
|
492
|
+
def __reset_flow_nodes(self) -> None:
|
|
485
493
|
"""
|
|
486
494
|
Private helper to reset the status and metrics for all nodes in the flow.
|
|
487
495
|
|
|
@@ -497,7 +505,7 @@ class Scheduler:
|
|
|
497
505
|
for step, index in self.__flow.get_nodes():
|
|
498
506
|
self.__metrics.clear(step, index)
|
|
499
507
|
|
|
500
|
-
def __clean_build_dir_full(self, recheck: bool = False):
|
|
508
|
+
def __clean_build_dir_full(self, recheck: bool = False) -> None:
|
|
501
509
|
"""
|
|
502
510
|
Remove stale build outputs from the current job directory to prepare for a fresh run.
|
|
503
511
|
|
|
@@ -531,7 +539,7 @@ class Scheduler:
|
|
|
531
539
|
else:
|
|
532
540
|
shutil.rmtree(os.path.join(cur_job_dir, delfile))
|
|
533
541
|
|
|
534
|
-
def __clean_build_dir_incr(self):
|
|
542
|
+
def __clean_build_dir_incr(self) -> None:
|
|
535
543
|
"""
|
|
536
544
|
Prune the job build directory to match the current flow and clean pending node directories.
|
|
537
545
|
|
|
@@ -568,7 +576,7 @@ class Scheduler:
|
|
|
568
576
|
with self.__tasks[(step, index)].runtime():
|
|
569
577
|
self.__tasks[(step, index)].clean_directory()
|
|
570
578
|
|
|
571
|
-
def configure_nodes(self):
|
|
579
|
+
def configure_nodes(self) -> None:
|
|
572
580
|
"""
|
|
573
581
|
Prepare and configure all flow nodes before execution, including loading prior run state,
|
|
574
582
|
running per-node setup, and marking nodes that require rerun.
|
|
@@ -686,7 +694,7 @@ class Scheduler:
|
|
|
686
694
|
f"{self.__name}.pkg.json"))
|
|
687
695
|
journal.stop()
|
|
688
696
|
|
|
689
|
-
def __check_display(self):
|
|
697
|
+
def __check_display(self) -> None:
|
|
690
698
|
"""
|
|
691
699
|
Private helper to automatically disable GUI display on headless systems.
|
|
692
700
|
|
|
@@ -701,7 +709,7 @@ class Scheduler:
|
|
|
701
709
|
self.__logger.warning("Setting [option,nodisplay] to True")
|
|
702
710
|
self.__project.set('option', 'nodisplay', True)
|
|
703
711
|
|
|
704
|
-
def __increment_job_name(self):
|
|
712
|
+
def __increment_job_name(self) -> bool:
|
|
705
713
|
"""
|
|
706
714
|
Private helper to auto-increment the jobname if ['option', 'jobincr'] is True.
|
|
707
715
|
|
|
@@ -11,7 +11,7 @@ import os.path
|
|
|
11
11
|
|
|
12
12
|
from logging.handlers import QueueHandler
|
|
13
13
|
|
|
14
|
-
from typing import List
|
|
14
|
+
from typing import List, Optional, Set, Tuple, TYPE_CHECKING
|
|
15
15
|
|
|
16
16
|
from siliconcompiler import utils, sc_open
|
|
17
17
|
from siliconcompiler import NodeStatus
|
|
@@ -21,7 +21,13 @@ from siliconcompiler.package import Resolver
|
|
|
21
21
|
from siliconcompiler.schema_support.record import RecordTime, RecordTool
|
|
22
22
|
from siliconcompiler.schema import Journal
|
|
23
23
|
from siliconcompiler.scheduler import send_messages
|
|
24
|
-
from siliconcompiler.utils.paths import workdir, jobdir, collectiondir
|
|
24
|
+
from siliconcompiler.utils.paths import workdir, jobdir, collectiondir, cwdir
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from siliconcompiler.project import Project
|
|
28
|
+
from siliconcompiler import Flowgraph, Task
|
|
29
|
+
from siliconcompiler.schema_support.record import RecordSchema
|
|
30
|
+
from siliconcompiler.schema_support.metric import MetricSchema
|
|
25
31
|
|
|
26
32
|
|
|
27
33
|
class SchedulerFlowReset(Exception):
|
|
@@ -38,7 +44,7 @@ class SchedulerNode:
|
|
|
38
44
|
|
|
39
45
|
"""
|
|
40
46
|
|
|
41
|
-
def __init__(self, project, step, index, replay=False):
|
|
47
|
+
def __init__(self, project: "Project", step: str, index: str, replay: bool = False):
|
|
42
48
|
"""
|
|
43
49
|
Initializes a SchedulerNode.
|
|
44
50
|
|
|
@@ -61,16 +67,16 @@ class SchedulerNode:
|
|
|
61
67
|
self.__project = project
|
|
62
68
|
|
|
63
69
|
self.__name = self.__project.name
|
|
64
|
-
self.__topmodule = self.__project.get(
|
|
70
|
+
self.__topmodule: str = self.__project.get(
|
|
65
71
|
"library",
|
|
66
72
|
self.__name,
|
|
67
73
|
"fileset",
|
|
68
74
|
self.__project.get("option", "fileset")[0],
|
|
69
75
|
"topmodule")
|
|
70
76
|
|
|
71
|
-
self.__job = self.__project.get('option', 'jobname')
|
|
72
|
-
self.__record_user_info = self.__project.get(
|
|
73
|
-
|
|
77
|
+
self.__job: str = self.__project.get('option', 'jobname')
|
|
78
|
+
self.__record_user_info: bool = self.__project.get(
|
|
79
|
+
"option", "track", step=self.__step, index=self.__index)
|
|
74
80
|
self.__pipe = None
|
|
75
81
|
self.__failed_log_lines = 20
|
|
76
82
|
self.__error = False
|
|
@@ -84,11 +90,11 @@ class SchedulerNode:
|
|
|
84
90
|
self.__enforce_inputfiles = True
|
|
85
91
|
self.__enforce_outputfiles = True
|
|
86
92
|
|
|
87
|
-
flow = self.__project.get('option', 'flow')
|
|
88
|
-
self.__is_entry_node = (self.__step, self.__index) in \
|
|
93
|
+
flow: str = self.__project.get('option', 'flow')
|
|
94
|
+
self.__is_entry_node: bool = (self.__step, self.__index) in \
|
|
89
95
|
self.__project.get("flowgraph", flow, field="schema").get_entry_nodes()
|
|
90
96
|
|
|
91
|
-
self.__cwd = self.__project
|
|
97
|
+
self.__cwd = cwdir(self.__project)
|
|
92
98
|
self.__jobworkdir = jobdir(self.__project)
|
|
93
99
|
self.__workdir = workdir(self.__project, step=self.__step, index=self.__index)
|
|
94
100
|
self.__manifests = {
|
|
@@ -120,7 +126,7 @@ class SchedulerNode:
|
|
|
120
126
|
self.__task = prev_task
|
|
121
127
|
|
|
122
128
|
@staticmethod
|
|
123
|
-
def init(project):
|
|
129
|
+
def init(project: "Project") -> None:
|
|
124
130
|
"""Static placeholder for future initialization logic."""
|
|
125
131
|
pass
|
|
126
132
|
|
|
@@ -150,7 +156,7 @@ class SchedulerNode:
|
|
|
150
156
|
"""bool: True if the node has encountered an error."""
|
|
151
157
|
return self.__error
|
|
152
158
|
|
|
153
|
-
def set_builtin(self):
|
|
159
|
+
def set_builtin(self) -> None:
|
|
154
160
|
"""Flags this node as a 'builtin' node."""
|
|
155
161
|
self.__builtin = True
|
|
156
162
|
|
|
@@ -165,7 +171,7 @@ class SchedulerNode:
|
|
|
165
171
|
return self.project.logger
|
|
166
172
|
|
|
167
173
|
@property
|
|
168
|
-
def project(self):
|
|
174
|
+
def project(self) -> "Project":
|
|
169
175
|
"""Project: The parent Project object."""
|
|
170
176
|
return self.__project
|
|
171
177
|
|
|
@@ -220,11 +226,11 @@ class SchedulerNode:
|
|
|
220
226
|
return self.__replay
|
|
221
227
|
|
|
222
228
|
@property
|
|
223
|
-
def task(self):
|
|
229
|
+
def task(self) -> "Task":
|
|
224
230
|
"""Task: The task object associated with this node."""
|
|
225
231
|
return self.__task
|
|
226
232
|
|
|
227
|
-
def get_manifest(self, input=False):
|
|
233
|
+
def get_manifest(self, input: bool = False) -> str:
|
|
228
234
|
"""
|
|
229
235
|
Gets the path to the input or output manifest file for this node.
|
|
230
236
|
|
|
@@ -239,7 +245,7 @@ class SchedulerNode:
|
|
|
239
245
|
return self.__manifests["input"]
|
|
240
246
|
return self.__manifests["output"]
|
|
241
247
|
|
|
242
|
-
def get_log(self, type="exe"):
|
|
248
|
+
def get_log(self, type: str = "exe") -> str:
|
|
243
249
|
"""
|
|
244
250
|
Gets the path to a specific log file for this node.
|
|
245
251
|
|
|
@@ -257,18 +263,18 @@ class SchedulerNode:
|
|
|
257
263
|
return self.__logs[type]
|
|
258
264
|
|
|
259
265
|
@property
|
|
260
|
-
def replay_script(self):
|
|
266
|
+
def replay_script(self) -> str:
|
|
261
267
|
"""str: The path to the shell script for replaying this node's execution."""
|
|
262
268
|
return self.__replay_script
|
|
263
269
|
|
|
264
270
|
@property
|
|
265
|
-
def threads(self):
|
|
271
|
+
def threads(self) -> int:
|
|
266
272
|
"""int: The number of threads allocated for this node's task."""
|
|
267
273
|
with self.__task.runtime(self) as task:
|
|
268
274
|
thread_count = task.get("threads")
|
|
269
275
|
return thread_count
|
|
270
276
|
|
|
271
|
-
def set_queue(self, pipe, queue):
|
|
277
|
+
def set_queue(self, pipe, queue) -> None:
|
|
272
278
|
"""
|
|
273
279
|
Configures the multiprocessing queue and pipe for inter-process communication.
|
|
274
280
|
|
|
@@ -284,7 +290,7 @@ class SchedulerNode:
|
|
|
284
290
|
# Reinit
|
|
285
291
|
self.__setup_schema_access()
|
|
286
292
|
|
|
287
|
-
def __setup_schema_access(self):
|
|
293
|
+
def __setup_schema_access(self) -> None:
|
|
288
294
|
"""
|
|
289
295
|
Private helper to set up direct access to schema objects.
|
|
290
296
|
|
|
@@ -293,15 +299,15 @@ class SchedulerNode:
|
|
|
293
299
|
access to configuration and results.
|
|
294
300
|
"""
|
|
295
301
|
flow = self.__project.get('option', 'flow')
|
|
296
|
-
self.__flow = self.__project.get("flowgraph", flow, field="schema")
|
|
302
|
+
self.__flow: "Flowgraph" = self.__project.get("flowgraph", flow, field="schema")
|
|
297
303
|
|
|
298
304
|
tool = self.__flow.get(self.__step, self.__index, 'tool')
|
|
299
305
|
task = self.__flow.get(self.__step, self.__index, 'task')
|
|
300
|
-
self.__task = self.__project.get("tool", tool, "task", task, field="schema")
|
|
301
|
-
self.__record = self.__project.get("record", field="schema")
|
|
302
|
-
self.__metrics = self.__project.get("metric", field="schema")
|
|
306
|
+
self.__task: "Task" = self.__project.get("tool", tool, "task", task, field="schema")
|
|
307
|
+
self.__record: "RecordSchema" = self.__project.get("record", field="schema")
|
|
308
|
+
self.__metrics: "MetricSchema" = self.__project.get("metric", field="schema")
|
|
303
309
|
|
|
304
|
-
def _init_run_logger(self):
|
|
310
|
+
def _init_run_logger(self) -> None:
|
|
305
311
|
"""
|
|
306
312
|
Initializes and configures the logger for the node's execution.
|
|
307
313
|
|
|
@@ -318,7 +324,7 @@ class SchedulerNode:
|
|
|
318
324
|
self.__project._logger_console.setFormatter(formatter)
|
|
319
325
|
self.logger.addHandler(self.__project._logger_console)
|
|
320
326
|
|
|
321
|
-
def halt(self, msg=None):
|
|
327
|
+
def halt(self, msg: Optional[str] = None) -> None:
|
|
322
328
|
"""
|
|
323
329
|
Stops the node's execution due to an error.
|
|
324
330
|
|
|
@@ -341,7 +347,7 @@ class SchedulerNode:
|
|
|
341
347
|
send_messages.send(self.__project, "fail", self.__step, self.__index)
|
|
342
348
|
sys.exit(1)
|
|
343
349
|
|
|
344
|
-
def setup(self):
|
|
350
|
+
def setup(self) -> bool:
|
|
345
351
|
"""
|
|
346
352
|
Runs the setup() method for the node's assigned task.
|
|
347
353
|
|
|
@@ -376,7 +382,7 @@ class SchedulerNode:
|
|
|
376
382
|
|
|
377
383
|
return True
|
|
378
384
|
|
|
379
|
-
def check_previous_run_status(self, previous_run):
|
|
385
|
+
def check_previous_run_status(self, previous_run: "SchedulerNode") -> bool:
|
|
380
386
|
"""
|
|
381
387
|
Determine whether a prior run is compatible and completed successfully for use as
|
|
382
388
|
an incremental build starting point.
|
|
@@ -435,7 +441,8 @@ class SchedulerNode:
|
|
|
435
441
|
|
|
436
442
|
return True
|
|
437
443
|
|
|
438
|
-
def check_values_changed(self, previous_run, keys)
|
|
444
|
+
def check_values_changed(self, previous_run: "SchedulerNode", keys: Set[Tuple[str, ...]]) \
|
|
445
|
+
-> bool:
|
|
439
446
|
"""
|
|
440
447
|
Checks if any specified schema parameter values have changed.
|
|
441
448
|
|
|
@@ -470,7 +477,8 @@ class SchedulerNode:
|
|
|
470
477
|
|
|
471
478
|
return False
|
|
472
479
|
|
|
473
|
-
def check_files_changed(self, previous_run
|
|
480
|
+
def check_files_changed(self, previous_run: "SchedulerNode",
|
|
481
|
+
previous_time: float, keys: Set[Tuple[str, ...]]) -> bool:
|
|
474
482
|
"""
|
|
475
483
|
Checks if any specified file-based parameters have changed.
|
|
476
484
|
|
|
@@ -537,7 +545,7 @@ class SchedulerNode:
|
|
|
537
545
|
|
|
538
546
|
return False
|
|
539
547
|
|
|
540
|
-
def get_check_changed_keys(self):
|
|
548
|
+
def get_check_changed_keys(self) -> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
|
|
541
549
|
"""
|
|
542
550
|
Gathers all schema keys that could trigger a re-run if changed.
|
|
543
551
|
|
|
@@ -577,7 +585,7 @@ class SchedulerNode:
|
|
|
577
585
|
|
|
578
586
|
return value_keys, path_keys
|
|
579
587
|
|
|
580
|
-
def requires_run(self):
|
|
588
|
+
def requires_run(self) -> bool:
|
|
581
589
|
"""
|
|
582
590
|
Determines if the node needs to be re-run.
|
|
583
591
|
|
|
@@ -602,11 +610,11 @@ class SchedulerNode:
|
|
|
602
610
|
if os.path.exists(self.__manifests["input"]):
|
|
603
611
|
previous_node_time = os.path.getmtime(self.__manifests["input"])
|
|
604
612
|
try:
|
|
605
|
-
|
|
613
|
+
i_project: Project = Project.from_manifest(filepath=self.__manifests["input"])
|
|
606
614
|
except: # noqa E722
|
|
607
615
|
self.logger.debug("Input manifest failed to load")
|
|
608
616
|
return True
|
|
609
|
-
previous_node = SchedulerNode(
|
|
617
|
+
previous_node = SchedulerNode(i_project, self.__step, self.__index)
|
|
610
618
|
else:
|
|
611
619
|
# No manifest found so assume rerun is needed
|
|
612
620
|
self.logger.debug("Previous run did not generate input manifest")
|
|
@@ -615,11 +623,11 @@ class SchedulerNode:
|
|
|
615
623
|
previous_node_end = None
|
|
616
624
|
if os.path.exists(self.__manifests["output"]):
|
|
617
625
|
try:
|
|
618
|
-
|
|
626
|
+
o_project = Project.from_manifest(filepath=self.__manifests["output"])
|
|
619
627
|
except: # noqa E722
|
|
620
628
|
self.logger.debug("Output manifest failed to load")
|
|
621
629
|
return True
|
|
622
|
-
previous_node_end = SchedulerNode(
|
|
630
|
+
previous_node_end = SchedulerNode(o_project, self.__step, self.__index)
|
|
623
631
|
else:
|
|
624
632
|
# No manifest found so assume rerun is needed
|
|
625
633
|
self.logger.debug("Previous run did not generate output manifest")
|
|
@@ -655,7 +663,7 @@ class SchedulerNode:
|
|
|
655
663
|
|
|
656
664
|
return False
|
|
657
665
|
|
|
658
|
-
def setup_input_directory(self):
|
|
666
|
+
def setup_input_directory(self) -> None:
|
|
659
667
|
"""
|
|
660
668
|
Prepares the 'inputs/' directory for the node's execution.
|
|
661
669
|
|
|
@@ -700,7 +708,7 @@ class SchedulerNode:
|
|
|
700
708
|
os.rename(f'{self.__workdir}/inputs/{outfile.name}',
|
|
701
709
|
f'{self.__workdir}/inputs/{new_name}')
|
|
702
710
|
|
|
703
|
-
def validate(self):
|
|
711
|
+
def validate(self) -> bool:
|
|
704
712
|
"""
|
|
705
713
|
Performs pre-run validation checks.
|
|
706
714
|
|
|
@@ -762,7 +770,7 @@ class SchedulerNode:
|
|
|
762
770
|
|
|
763
771
|
return not error
|
|
764
772
|
|
|
765
|
-
def summarize(self):
|
|
773
|
+
def summarize(self) -> None:
|
|
766
774
|
"""Prints a post-run summary of metrics to the logger."""
|
|
767
775
|
for metric in ['errors', 'warnings']:
|
|
768
776
|
val = self.__metrics.get(metric, step=self.__step, index=self.__index)
|
|
@@ -772,7 +780,7 @@ class SchedulerNode:
|
|
|
772
780
|
walltime = self.__metrics.get("tasktime", step=self.__step, index=self.__index)
|
|
773
781
|
self.logger.info(f"Finished task in {walltime:.2f}s")
|
|
774
782
|
|
|
775
|
-
def run(self):
|
|
783
|
+
def run(self) -> None:
|
|
776
784
|
"""
|
|
777
785
|
Executes the full lifecycle for this node.
|
|
778
786
|
|
|
@@ -861,7 +869,7 @@ class SchedulerNode:
|
|
|
861
869
|
if self.__pipe:
|
|
862
870
|
self.__pipe.send(Resolver.get_cache(self.__project))
|
|
863
871
|
|
|
864
|
-
def execute(self):
|
|
872
|
+
def execute(self) -> None:
|
|
865
873
|
"""
|
|
866
874
|
Handles the core tool execution logic.
|
|
867
875
|
|
|
@@ -1006,7 +1014,7 @@ class SchedulerNode:
|
|
|
1006
1014
|
|
|
1007
1015
|
send_messages.send(self.__project, "end", self.__step, self.__index)
|
|
1008
1016
|
|
|
1009
|
-
def __generate_testcase(self):
|
|
1017
|
+
def __generate_testcase(self) -> None:
|
|
1010
1018
|
"""
|
|
1011
1019
|
Private helper to generate a test case upon failure.
|
|
1012
1020
|
|
|
@@ -1041,7 +1049,7 @@ class SchedulerNode:
|
|
|
1041
1049
|
hash_files=self.__hash,
|
|
1042
1050
|
verbose_collect=False)
|
|
1043
1051
|
|
|
1044
|
-
def check_logfile(self):
|
|
1052
|
+
def check_logfile(self) -> None:
|
|
1045
1053
|
"""
|
|
1046
1054
|
Parses the tool execution log file for patterns.
|
|
1047
1055
|
|
|
@@ -1135,7 +1143,7 @@ class SchedulerNode:
|
|
|
1135
1143
|
|
|
1136
1144
|
self.__task.record_metric(metric, value, source_file=sources)
|
|
1137
1145
|
|
|
1138
|
-
def __hash_files_pre_execute(self):
|
|
1146
|
+
def __hash_files_pre_execute(self) -> None:
|
|
1139
1147
|
"""Private helper to hash all relevant input files before execution."""
|
|
1140
1148
|
for task_key in ('refdir', 'prescript', 'postscript', 'script'):
|
|
1141
1149
|
self.__project.hash_files('tool', self.__task.tool(),
|
|
@@ -1154,7 +1162,7 @@ class SchedulerNode:
|
|
|
1154
1162
|
self.__project.hash_files(*args, step=access_step, index=access_index,
|
|
1155
1163
|
check=False, verbose=False)
|
|
1156
1164
|
|
|
1157
|
-
def __hash_files_post_execute(self):
|
|
1165
|
+
def __hash_files_post_execute(self) -> None:
|
|
1158
1166
|
"""Private helper to hash all output files after execution."""
|
|
1159
1167
|
# hash all outputs
|
|
1160
1168
|
self.__project.hash_files('tool', self.__task.tool(), 'task', self.__task.task(), 'output',
|
|
@@ -1173,14 +1181,14 @@ class SchedulerNode:
|
|
|
1173
1181
|
self.__project.hash_files(*args, step=access_step, index=access_index,
|
|
1174
1182
|
check=False, verbose=False)
|
|
1175
1183
|
|
|
1176
|
-
def __report_output_files(self):
|
|
1184
|
+
def __report_output_files(self) -> None:
|
|
1177
1185
|
"""
|
|
1178
1186
|
Private helper to check for missing or unexpected output files.
|
|
1179
1187
|
|
|
1180
1188
|
Compares the files found in the 'outputs/' directory against the
|
|
1181
1189
|
files expected by the task's schema. Reports errors if they don't match.
|
|
1182
1190
|
"""
|
|
1183
|
-
if self.
|
|
1191
|
+
if self.is_builtin:
|
|
1184
1192
|
return
|
|
1185
1193
|
|
|
1186
1194
|
error = False
|
|
@@ -1215,7 +1223,7 @@ class SchedulerNode:
|
|
|
1215
1223
|
if error and self.__enforce_outputfiles:
|
|
1216
1224
|
self.halt()
|
|
1217
1225
|
|
|
1218
|
-
def copy_from(self, source):
|
|
1226
|
+
def copy_from(self, source: str) -> None:
|
|
1219
1227
|
"""
|
|
1220
1228
|
Imports the results of this node from a different job run.
|
|
1221
1229
|
|
|
@@ -1258,12 +1266,14 @@ class SchedulerNode:
|
|
|
1258
1266
|
schema.set('option', 'jobname', self.__job)
|
|
1259
1267
|
schema.write_manifest(manifest)
|
|
1260
1268
|
|
|
1261
|
-
def clean_directory(self):
|
|
1269
|
+
def clean_directory(self) -> None:
|
|
1262
1270
|
"""Removes the working directory for this node."""
|
|
1263
1271
|
if os.path.exists(self.__workdir):
|
|
1264
1272
|
shutil.rmtree(self.__workdir)
|
|
1265
1273
|
|
|
1266
|
-
def archive(self, tar: tarfile.TarFile,
|
|
1274
|
+
def archive(self, tar: tarfile.TarFile,
|
|
1275
|
+
include: Optional[List[str]] = None,
|
|
1276
|
+
verbose: bool = False) -> None:
|
|
1267
1277
|
"""
|
|
1268
1278
|
Archives the node's results into a tar file.
|
|
1269
1279
|
|