From 0dab3f0fcaac5b30e9a85bfa2d0100c66ddf4423 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Thu, 2 Apr 2026 18:34:02 +0100 Subject: [PATCH] Rewrite how OneShotCfg.build_modes gets constructed This is a bit tricky because self.build_modes comes from parsing an hjson dictionary and is actually a list of dictionaries that describe build modes. These get parsed and converted to BuildMode objects by Mode.create_modes. I've written a rather silly loose check that makes sure the types look reasonable, which is enough to let us convince Pyright to allow the code to claim the correct eventual types. This commit also fixes an incorrect type in the second argument to create_modes. Signed-off-by: Rupert Swarbrick --- src/dvsim/flow/one_shot.py | 37 +++++++++++++++++++++++++++---------- src/dvsim/modes.py | 2 +- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/dvsim/flow/one_shot.py b/src/dvsim/flow/one_shot.py index c717eea2..71ffdb37 100644 --- a/src/dvsim/flow/one_shot.py +++ b/src/dvsim/flow/one_shot.py @@ -53,7 +53,7 @@ def __init__(self, flow_cfg_file, hjson_data, args, mk_config) -> None: self.dut = "" self.fusesoc_core = "" self.ral_spec = "" - self.build_modes = [] + self.build_modes: Sequence[BuildMode] = [] self.run_modes = [] self.regressions = [] self.max_msg_count = -1 @@ -110,17 +110,34 @@ def _expand(self) -> None: def _purge(self) -> None: assert self.scratch_path log.info("Purging scratch path %s", self.scratch_path) - rm_path(self.scratch_path) + rm_path(Path(self.scratch_path)) def _create_objects(self) -> None: - # Create build and run modes objects - build_modes = Mode.create_modes(BuildMode, self.build_modes) - self.build_modes = build_modes - - # All defined build modes are being built, h - # ence extend all with the global opts. - for build_mode in build_modes: - build_mode.build_opts.extend(self.build_opts) + # Create build modes objects based on the names that were stored in + # self.build_modes by the superclass constructor's call to + # _merge_hjson. + # + # We've lied to the type checker about the type of self.build_modes, + # giving it the type that it will contain after this function is + # complete. + mode_dicts: list[dict[object, object]] = [] + for mode_dict in self.build_modes: + if not isinstance(mode_dict, dict): + msg = f"Found a build mode item of {mode_dict} when we expected a dict." + raise TypeError(msg) + + mode_dicts.append(mode_dict) + + base_modes: Sequence[Mode] = Mode.create_modes(BuildMode, mode_dicts) + + # All defined build modes are being built, so should be extended with + # the global opts. Tighten up the inferred type at the same time. + self.build_modes = [] + for mode in base_modes: + if not isinstance(mode, BuildMode): + raise TypeError("create_modes returned the wrong type") + mode.build_opts.extend(self.build_opts) + self.build_modes.append(mode) def _print_list(self) -> None: for list_item in self.list_items: diff --git a/src/dvsim/modes.py b/src/dvsim/modes.py index 9f944518..f7ae265c 100644 --- a/src/dvsim/modes.py +++ b/src/dvsim/modes.py @@ -146,7 +146,7 @@ def merge_mode(self, mode: "Mode") -> None: return True @staticmethod - def create_modes(mode_type: "type[Mode]", mdicts: Mapping) -> Sequence["Mode"]: + def create_modes(mode_type: "type[Mode]", mdicts: Sequence[Mapping]) -> Sequence["Mode"]: """Create modes of type mode_type. Use the given list of raw dicts Process dependencies.