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.
Files changed (49) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/_common.py +3 -2
  3. siliconcompiler/apps/sc_dashboard.py +3 -1
  4. siliconcompiler/apps/sc_install.py +149 -37
  5. siliconcompiler/apps/smake.py +9 -3
  6. siliconcompiler/checklist.py +3 -3
  7. siliconcompiler/data/demo_fpga/z1000_yosys_config.json +24 -0
  8. siliconcompiler/design.py +51 -45
  9. siliconcompiler/flowgraph.py +2 -2
  10. siliconcompiler/library.py +23 -12
  11. siliconcompiler/package/__init__.py +77 -49
  12. siliconcompiler/package/git.py +11 -6
  13. siliconcompiler/package/github.py +11 -6
  14. siliconcompiler/package/https.py +6 -4
  15. siliconcompiler/pdk.py +23 -16
  16. siliconcompiler/scheduler/scheduler.py +30 -22
  17. siliconcompiler/scheduler/schedulernode.py +60 -50
  18. siliconcompiler/scheduler/taskscheduler.py +52 -32
  19. siliconcompiler/schema/baseschema.py +88 -69
  20. siliconcompiler/schema/docs/schemagen.py +4 -3
  21. siliconcompiler/schema/editableschema.py +5 -5
  22. siliconcompiler/schema/journal.py +19 -13
  23. siliconcompiler/schema/namedschema.py +16 -10
  24. siliconcompiler/schema/parameter.py +64 -37
  25. siliconcompiler/schema/parametervalue.py +126 -80
  26. siliconcompiler/schema/safeschema.py +16 -7
  27. siliconcompiler/schema/utils.py +3 -1
  28. siliconcompiler/schema_support/cmdlineschema.py +9 -9
  29. siliconcompiler/schema_support/dependencyschema.py +12 -7
  30. siliconcompiler/schema_support/filesetschema.py +15 -10
  31. siliconcompiler/schema_support/metric.py +29 -17
  32. siliconcompiler/schema_support/packageschema.py +2 -2
  33. siliconcompiler/schema_support/pathschema.py +30 -18
  34. siliconcompiler/schema_support/record.py +30 -23
  35. siliconcompiler/tool.py +265 -210
  36. siliconcompiler/tools/opensta/timing.py +13 -0
  37. siliconcompiler/tools/yosys/syn_fpga.py +3 -2
  38. siliconcompiler/toolscripts/_tools.json +3 -3
  39. siliconcompiler/utils/__init__.py +23 -16
  40. siliconcompiler/utils/curation.py +11 -5
  41. siliconcompiler/utils/multiprocessing.py +16 -14
  42. siliconcompiler/utils/paths.py +24 -12
  43. siliconcompiler/utils/units.py +16 -12
  44. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/METADATA +3 -4
  45. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/RECORD +49 -48
  46. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/entry_points.txt +4 -3
  47. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/WHEEL +0 -0
  48. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/licenses/LICENSE +0 -0
  49. {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=self.__project.get('option', 'prune'))
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("option", "track",
73
- step=self.__step, index=self.__index)
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._Project__cwd
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, previous_time, keys):
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
- project = Project.from_manifest(filepath=self.__manifests["input"])
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(project, self.__step, self.__index)
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
- project = Project.from_manifest(filepath=self.__manifests["output"])
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(project, self.__step, self.__index)
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.__task.tool() == 'builtin':
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, include: List[str] = None, verbose: bool = False):
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