77import os
88import pprint
99import sys
10- from collections .abc import Mapping
10+ from abc import ABC , abstractmethod
11+ from collections .abc import Mapping , Sequence
1112from pathlib import Path
13+ from typing import ClassVar
1214
1315import hjson
1416
2729
2830
2931# Interface class for extensions.
30- class FlowCfg :
32+ class FlowCfg ( ABC ) :
3133 """Base class for the different flows supported by dvsim.py.
3234
3335 The constructor expects some parsed hjson data. Create these objects with
@@ -41,9 +43,10 @@ class FlowCfg:
4143
4244 # Can be overridden in subclasses to configure which wildcards to ignore
4345 # when expanding hjson.
44- ignored_wildcards = []
46+ ignored_wildcards : ClassVar = []
4547
4648 def __str__ (self ) -> str :
49+ """Get string representation of the flow config."""
4750 return pprint .pformat (self .__dict__ )
4851
4952 def __init__ (self , flow_cfg_file , hjson_data , args , mk_config ) -> None :
@@ -87,7 +90,7 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None:
8790 # For a primary cfg, it is the aggregated list of all deploy objects
8891 # under self.cfgs. For a non-primary cfg, it is the list of items
8992 # slated for dispatch.
90- self .deploy = []
93+ self .deploy : Sequence [ Deploy ] = []
9194
9295 # Timestamp
9396 self .timestamp_long = args .timestamp_long
@@ -98,7 +101,7 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None:
98101 self .rel_path = ""
99102 self .results_title = ""
100103 self .revision = ""
101- self .css_file = os . path . join ( Path (os . path . realpath ( __file__ )) .parent , "style.css" )
104+ self .css_file = Path (__file__ ). resolve () .parent / "style.css"
102105 # `self.results_*` below will be updated after `self.rel_path` and
103106 # `self.scratch_base_root` variables are updated.
104107 self .results_dir = ""
@@ -151,7 +154,7 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None:
151154 # Run any final checks
152155 self ._post_init ()
153156
154- def _merge_hjson (self , hjson_data ) -> None :
157+ def _merge_hjson (self , hjson_data : Mapping ) -> None :
155158 """Take hjson data and merge it into self.__dict__.
156159
157160 Subclasses that need to do something just before the merge should
@@ -162,7 +165,7 @@ def _merge_hjson(self, hjson_data) -> None:
162165 set_target_attribute (self .flow_cfg_file , self .__dict__ , key , value )
163166
164167 def _expand (self ) -> None :
165- """Called to expand wildcards after merging hjson.
168+ """Expand wildcards after merging hjson.
166169
167170 Subclasses can override this to do something just before expansion.
168171
@@ -237,8 +240,9 @@ def _load_child_cfg(self, entry, mk_config) -> None:
237240 )
238241 sys .exit (1 )
239242
240- def _conv_inline_cfg_to_hjson (self , idict ) :
243+ def _conv_inline_cfg_to_hjson (self , idict : Mapping ) -> str | None :
241244 """Dump a temp hjson file in the scratch space from input dict.
245+
242246 This method is to be called only by a primary cfg.
243247 """
244248 if not self .is_primary_cfg :
@@ -259,8 +263,10 @@ def _conv_inline_cfg_to_hjson(self, idict):
259263
260264 # Create the file and dump the dict as hjson
261265 log .verbose ('Dumping inline cfg "%s" in hjson to:\n %s' , name , temp_cfg_file )
266+
262267 try :
263268 Path (temp_cfg_file ).write_text (hjson .dumps (idict , for_json = True ))
269+
264270 except Exception as e :
265271 log .exception (
266272 'Failed to hjson-dump temp cfg file"%s" for "%s"(will be skipped!) due to:\n %s' ,
@@ -332,6 +338,7 @@ def _do_override(self, ov_name: str, ov_value: object) -> None:
332338 log .error ('Override key "%s" not found in the cfg!' , ov_name )
333339 sys .exit (1 )
334340
341+ @abstractmethod
335342 def _purge (self ) -> None :
336343 """Purge the existing scratch areas in preparation for the new run."""
337344
@@ -340,6 +347,7 @@ def purge(self) -> None:
340347 for item in self .cfgs :
341348 item ._purge ()
342349
350+ @abstractmethod
343351 def _print_list (self ) -> None :
344352 """Print the list of available items that can be kicked off."""
345353
@@ -370,12 +378,13 @@ def prune_selected_cfgs(self) -> None:
370378 # Filter configurations
371379 self .cfgs = [c for c in self .cfgs if c .name in self .select_cfgs ]
372380
381+ @abstractmethod
373382 def _create_deploy_objects (self ) -> None :
374383 """Create deploy objects from items that were passed on for being run.
384+
375385 The deploy objects for build and run are created from the objects that
376386 were created from the create_objects() method.
377387 """
378- return
379388
380389 def create_deploy_objects (self ) -> None :
381390 """Public facing API for _create_deploy_objects()."""
@@ -389,7 +398,7 @@ def create_deploy_objects(self) -> None:
389398 for item in self .cfgs :
390399 item ._create_deploy_objects ()
391400
392- def deploy_objects (self ):
401+ def deploy_objects (self ) -> Mapping [ Deploy , str ] :
393402 """Public facing API for deploying all available objects.
394403
395404 Runs each job and returns a map from item to status.
@@ -402,21 +411,26 @@ def deploy_objects(self):
402411 log .error ("Nothing to run!" )
403412 sys .exit (1 )
404413
405- return Scheduler (deploy , get_launcher_cls (), self .interactive ).run ()
414+ return Scheduler (
415+ items = deploy ,
416+ launcher_cls = get_launcher_cls (),
417+ interactive = self .interactive ,
418+ ).run ()
406419
407- def _gen_results (self , results : Mapping [Deploy , str ]) -> None :
408- """Generate results.
420+ @abstractmethod
421+ def _gen_results (self , results : Mapping [Deploy , str ]) -> str :
422+ """Generate flow results.
409423
410- The function is called after the flow has completed. It collates the
411- status of all run targets and generates a dict. It parses the log
424+ The function is called after the flow has completed. It collates
425+ the status of all run targets and generates a dict. It parses the log
412426 to identify the errors, warnings and failures as applicable. It also
413427 prints the full list of failures for debug / triage to the final
414428 report, which is in markdown format.
415429
416430 results should be a dictionary mapping deployed item to result.
417431 """
418432
419- def gen_results (self , results ) -> None :
433+ def gen_results (self , results : Mapping [ Deploy , str ] ) -> None :
420434 """Public facing API for _gen_results().
421435
422436 results should be a dictionary mapping deployed item to result.
@@ -437,6 +451,7 @@ def gen_results(self, results) -> None:
437451 self .gen_results_summary ()
438452 self .write_results (self .results_html_name , self .results_summary_md )
439453
454+ @abstractmethod
440455 def gen_results_summary (self ) -> None :
441456 """Public facing API to generate summary results for each IP/cfg file."""
442457
@@ -468,4 +483,5 @@ def _get_results_page_link(self, relative_to: str, link_text: str = "") -> str:
468483 return f"[{ link_text } ]({ relative_link } )"
469484
470485 def has_errors (self ) -> bool :
486+ """Return error state."""
471487 return self .errors_seen
0 commit comments