7
7
import os
8
8
import pprint
9
9
import sys
10
- from collections .abc import Mapping
10
+ from abc import ABC , abstractmethod
11
+ from collections .abc import Mapping , Sequence
11
12
from pathlib import Path
13
+ from typing import ClassVar
12
14
13
15
import hjson
14
16
27
29
28
30
29
31
# Interface class for extensions.
30
- class FlowCfg :
32
+ class FlowCfg ( ABC ) :
31
33
"""Base class for the different flows supported by dvsim.py.
32
34
33
35
The constructor expects some parsed hjson data. Create these objects with
@@ -41,9 +43,10 @@ class FlowCfg:
41
43
42
44
# Can be overridden in subclasses to configure which wildcards to ignore
43
45
# when expanding hjson.
44
- ignored_wildcards = []
46
+ ignored_wildcards : ClassVar = []
45
47
46
48
def __str__ (self ) -> str :
49
+ """Get string representation of the flow config."""
47
50
return pprint .pformat (self .__dict__ )
48
51
49
52
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:
87
90
# For a primary cfg, it is the aggregated list of all deploy objects
88
91
# under self.cfgs. For a non-primary cfg, it is the list of items
89
92
# slated for dispatch.
90
- self .deploy = []
93
+ self .deploy : Sequence [ Deploy ] = []
91
94
92
95
# Timestamp
93
96
self .timestamp_long = args .timestamp_long
@@ -98,7 +101,7 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None:
98
101
self .rel_path = ""
99
102
self .results_title = ""
100
103
self .revision = ""
101
- self .css_file = os . path . join ( Path (os .path .realpath (__file__ )).parent , "style.css" )
104
+ self .css_file = Path (os .path .realpath (__file__ )).parent / "style.css"
102
105
# `self.results_*` below will be updated after `self.rel_path` and
103
106
# `self.scratch_base_root` variables are updated.
104
107
self .results_dir = ""
@@ -132,7 +135,9 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None:
132
135
self ._load_child_cfg (entry , mk_config )
133
136
134
137
if self .rel_path == "" :
135
- self .rel_path = Path (self .flow_cfg_file ).parent .replace (self .proj_root + "/" , "" )
138
+ self .rel_path = str (
139
+ Path (self .flow_cfg_file ).parent .relative_to (self .proj_root ),
140
+ )
136
141
137
142
# Process overrides before substituting wildcards
138
143
self ._process_overrides ()
@@ -149,7 +154,7 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None:
149
154
# Run any final checks
150
155
self ._post_init ()
151
156
152
- def _merge_hjson (self , hjson_data ) -> None :
157
+ def _merge_hjson (self , hjson_data : Mapping ) -> None :
153
158
"""Take hjson data and merge it into self.__dict__.
154
159
155
160
Subclasses that need to do something just before the merge should
@@ -160,7 +165,7 @@ def _merge_hjson(self, hjson_data) -> None:
160
165
set_target_attribute (self .flow_cfg_file , self .__dict__ , key , value )
161
166
162
167
def _expand (self ) -> None :
163
- """Called to expand wildcards after merging hjson.
168
+ """Expand wildcards after merging hjson.
164
169
165
170
Subclasses can override this to do something just before expansion.
166
171
@@ -235,8 +240,9 @@ def _load_child_cfg(self, entry, mk_config) -> None:
235
240
)
236
241
sys .exit (1 )
237
242
238
- def _conv_inline_cfg_to_hjson (self , idict ) :
243
+ def _conv_inline_cfg_to_hjson (self , idict : Mapping ) -> str | None :
239
244
"""Dump a temp hjson file in the scratch space from input dict.
245
+
240
246
This method is to be called only by a primary cfg.
241
247
"""
242
248
if not self .is_primary_cfg :
@@ -257,9 +263,11 @@ def _conv_inline_cfg_to_hjson(self, idict):
257
263
258
264
# Create the file and dump the dict as hjson
259
265
log .verbose ('Dumping inline cfg "%s" in hjson to:\n %s' , name , temp_cfg_file )
266
+
260
267
try :
261
268
Path (temp_cfg_file ).write_text (hjson .dumps (idict , for_json = True ))
262
- except Exception as e :
269
+
270
+ except Exception as e : # noqa: BLE001
263
271
log .exception (
264
272
'Failed to hjson-dump temp cfg file"%s" for "%s"(will be skipped!) due to:\n %s' ,
265
273
temp_cfg_file ,
@@ -330,6 +338,7 @@ def _do_override(self, ov_name: str, ov_value: object) -> None:
330
338
log .error ('Override key "%s" not found in the cfg!' , ov_name )
331
339
sys .exit (1 )
332
340
341
+ @abstractmethod
333
342
def _purge (self ) -> None :
334
343
"""Purge the existing scratch areas in preparation for the new run."""
335
344
@@ -338,6 +347,7 @@ def purge(self) -> None:
338
347
for item in self .cfgs :
339
348
item ._purge ()
340
349
350
+ @abstractmethod
341
351
def _print_list (self ) -> None :
342
352
"""Print the list of available items that can be kicked off."""
343
353
@@ -368,12 +378,13 @@ def prune_selected_cfgs(self) -> None:
368
378
# Filter configurations
369
379
self .cfgs = [c for c in self .cfgs if c .name in self .select_cfgs ]
370
380
381
+ @abstractmethod
371
382
def _create_deploy_objects (self ) -> None :
372
383
"""Create deploy objects from items that were passed on for being run.
384
+
373
385
The deploy objects for build and run are created from the objects that
374
386
were created from the create_objects() method.
375
387
"""
376
- return
377
388
378
389
def create_deploy_objects (self ) -> None :
379
390
"""Public facing API for _create_deploy_objects()."""
@@ -387,7 +398,7 @@ def create_deploy_objects(self) -> None:
387
398
for item in self .cfgs :
388
399
item ._create_deploy_objects ()
389
400
390
- def deploy_objects (self ):
401
+ def deploy_objects (self ) -> Mapping [ Deploy , str ] :
391
402
"""Public facing API for deploying all available objects.
392
403
393
404
Runs each job and returns a map from item to status.
@@ -400,21 +411,26 @@ def deploy_objects(self):
400
411
log .error ("Nothing to run!" )
401
412
sys .exit (1 )
402
413
403
- 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 ()
404
419
405
- def _gen_results (self , results : Mapping [Deploy , str ]) -> None :
406
- """Generate results.
420
+ @abstractmethod
421
+ def _gen_results (self , results : Mapping [Deploy , str ]) -> str :
422
+ """Generate flow results.
407
423
408
- The function is called after the flow has completed. It collates the
409
- 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
410
426
to identify the errors, warnings and failures as applicable. It also
411
427
prints the full list of failures for debug / triage to the final
412
428
report, which is in markdown format.
413
429
414
430
results should be a dictionary mapping deployed item to result.
415
431
"""
416
432
417
- def gen_results (self , results ) -> None :
433
+ def gen_results (self , results : Mapping [ Deploy , str ] ) -> None :
418
434
"""Public facing API for _gen_results().
419
435
420
436
results should be a dictionary mapping deployed item to result.
@@ -435,6 +451,7 @@ def gen_results(self, results) -> None:
435
451
self .gen_results_summary ()
436
452
self .write_results (self .results_html_name , self .results_summary_md )
437
453
454
+ @abstractmethod
438
455
def gen_results_summary (self ) -> None :
439
456
"""Public facing API to generate summary results for each IP/cfg file."""
440
457
@@ -466,4 +483,5 @@ def _get_results_page_link(self, relative_to: str, link_text: str = "") -> str:
466
483
return f"[{ link_text } ]({ relative_link } )"
467
484
468
485
def has_errors (self ) -> bool :
486
+ """Return error state."""
469
487
return self .errors_seen
0 commit comments