Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch Typechecker from mypy to pyright #850

Merged
merged 4 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,4 @@ jobs:
run: |
touch .venv/lib/python${{ matrix.python-version }}/site-packages/ruamel/py.typed
touch .venv/lib/python${{ matrix.python-version }}/site-packages/networkx/py.typed
poetry run mypy --namespace-packages -p hammer
poetry run mypy --namespace-packages -p tests
poetry run pyright
21 changes: 2 additions & 19 deletions doc/Hammer-Basics/Hammer-Setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,26 +135,9 @@ pytest tests/test_build_systems.py -k "flat_makefile" -rA -v
> PASSED tests/test_build_systems.py::TestHammerBuildSystems::test_flat_makefile
```

### Type Checking with mypy
### Type Checking with pyright

There is a [small issue with the ruamel.yaml package typechecking](https://github.com/python/mypy/issues/12664) which can be hacked around with (replace the python version with your own):

```shell
touch .venv/lib/python3.10/site-packages/ruamel/py.typed
touch .venv/lib/python3.10/site-packages/networkx/py.typed
```

Inside your poetry virtualenv, from the root of Hammer, run:

```shell
mypy --namespace-packages --warn-unused-ignores -p hammer

Success: no issues found in 146 source files

mypy --namespace-packages --warn-unused-ignores tests

Success: no issues found in 25 source files
```
Run: `poetry run pyright`

### Testing Different Python Versions with tox

Expand Down
2 changes: 1 addition & 1 deletion hammer/flowgraph/flowgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class Graph:
auto_auxiliary: bool = True

def __post_init__(self) -> None:
self.networkx = nx.DiGraph(Graph.insert_auxiliary_actions(self.edge_list) if self.auto_auxiliary else self.edge_list)
self.networkx = nx.DiGraph(Graph.insert_auxiliary_actions(self.edge_list) if self.auto_auxiliary else self.edge_list) # type: ignore

def verify(self) -> bool:
"""Checks if a graph is valid via its inputs and outputs.
Expand Down
1 change: 1 addition & 0 deletions hammer/generate_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def format_var(var):
var_type_instance_check = isinstance_check("List")
elif var.type.startswith("Optional"):
m = re.search(r"Optional\[(\S+)\]", var.type)
assert m
subtype = str(m.group(1))
var_type_instance_check = isinstance_check(subtype) + " or (value is None)"
attr_error_logic = "return None"
Expand Down
4 changes: 4 additions & 0 deletions hammer/par/openroad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,10 @@ def resize(self) -> bool:
tie_lo_cells = self.technology.get_special_cell_by_type(CellType.TieLoCell)
tie_hilo_cells = self.technology.get_special_cell_by_type(CellType.TieHiLoCell)

tie_hi_cell = ""
tie_hi_port = ""
tie_lo_cell = ""
tie_lo_port = ""
if len(tie_hi_cells) != 1 or len (tie_lo_cells) != 1:
self.logger.warning("Hi and Lo tiecells are unspecified or improperly specified and will not be added.")
elif tie_hi_cells[0].output_ports is None or tie_lo_cells[0].output_ports is None:
Expand Down
10 changes: 7 additions & 3 deletions hammer/power/voltus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# See LICENSE for licence details.

from typing import List, Dict, Optional, Callable
from typing import List, Dict, Optional, Callable, cast

import os
import json
Expand Down Expand Up @@ -303,7 +303,8 @@ def init_technology(self) -> bool:
rechar_libs = list(filter(lambda l: l.library.lef_file in mod_lefs, named_extra_libs))
macros = list(map(lambda l: l.library.name, rechar_libs)) # type: ignore
in_place_unique(macros)
self.macro_pgv_cells = macros
assert all([m is not None for m in macros])
self.macro_pgv_cells = cast(list[str], macros)

if len(self.macro_pgv_cells) > 0:
self.logger.info("Characterizing the following macros: {}".format(" ".join(self.macro_pgv_cells)))
Expand Down Expand Up @@ -359,7 +360,7 @@ def init_technology(self) -> bool:
if len(spice_corners) > 0:
options.extend(["-spice_corners", "{{", "} {".join(spice_corners), "}}"])
m_output.append("set_pg_library_mode {}".format(" ".join(options)))
m_output.append("write_pg_library -out_dir {}".format(os.path.join(self.macro_lib_dir, corner.name)))
m_output.append("write_pg_library -out_dir {}".format(os.path.join(self.macro_lib_dir, corner.name))) # type: ignore

else:
for corner in corners:
Expand Down Expand Up @@ -408,6 +409,9 @@ def init_design(self) -> bool:
verbose_append("check_pg_shorts -out_file shorts.rpt")

# TODO (daniel) deal with multiple power domains
vdd_net: str = ""
vss_net: str = ""
assert len(self.get_all_power_nets()) > 0 and len(self.get_all_ground_nets()) > 0
for power_net in self.get_all_power_nets():
vdd_net = power_net.name
for gnd_net in self.get_all_ground_nets():
Expand Down
5 changes: 4 additions & 1 deletion hammer/shell/yaml2json.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""
import sys
import yaml
import json
from hammer.config.yaml2json import convertArrays, compare

def load(f):
Expand All @@ -27,7 +28,9 @@ def yaml2json():
f2 = None
if len(sys.argv) > 2:
f2 = sys.argv[2]
obj = yaml.safe_load(load(f))
loaded_file = load(f)
assert loaded_file
obj = yaml.safe_load(loaded_file)
obj = convertArrays(obj)
outputContent = json.dumps(obj, indent=2)
obj2 = json.loads(outputContent)
Expand Down
16 changes: 14 additions & 2 deletions hammer/sim/vcs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ def run_simulation(self) -> bool:
force_regs_filename = self.force_regs_file_path
tb_prefix = self.get_setting("sim.inputs.tb_dut")
saif_mode = self.get_setting("sim.inputs.saif.mode")
saif_start_time: Optional[str] = None
saif_end_time: Optional[str] = None
saif_start_trigger_raw: Optional[str] = None
saif_end_trigger_raw: Optional[str] = None
if saif_mode == "time":
saif_start_time = self.get_setting("sim.inputs.saif.start_time")
saif_end_time = self.get_setting("sim.inputs.saif.end_time")
Expand All @@ -259,8 +263,10 @@ def run_simulation(self) -> bool:
if self.level == FlowLevel.RTL and saif_mode != "none":
find_regs_run_tcl = []
if saif_mode != "none":
stime: Optional[TimeValue] = None
if saif_mode == "time":
stime = TimeValue(saif_start_time[0])
assert saif_start_time
stime = TimeValue(saif_start_time)
find_regs_run_tcl.append("run {start}ns".format(start=stime.value_in_units("ns")))
elif saif_mode == "trigger_raw":
find_regs_run_tcl.append(saif_start_trigger_raw)
Expand All @@ -271,6 +277,8 @@ def run_simulation(self) -> bool:
find_regs_run_tcl.append("power {dut}".format(dut=tb_prefix))
find_regs_run_tcl.append("config endofsim noexit")
if saif_mode == "time":
assert saif_end_time
assert stime
etime = TimeValue(saif_end_time)
find_regs_run_tcl.append("run {end}ns".format(end=(etime.value_in_units("ns") - stime.value_in_units("ns"))))
elif saif_mode == "trigger_raw":
Expand All @@ -288,8 +296,10 @@ def run_simulation(self) -> bool:
find_regs_run_tcl = []
find_regs_run_tcl.append("source " + force_regs_filename)
if saif_mode != "none":
stime: Optional[TimeValue] = None
if saif_mode == "time":
stime = TimeValue(saif_start_time[0])
assert saif_start_time
stime = TimeValue(saif_start_time)
find_regs_run_tcl.append("run {start}ns".format(start=stime.value_in_units("ns")))
elif saif_mode == "trigger_raw":
find_regs_run_tcl.append(saif_start_trigger_raw)
Expand All @@ -301,6 +311,8 @@ def run_simulation(self) -> bool:
find_regs_run_tcl.append("power {dut}".format(dut=tb_prefix))
find_regs_run_tcl.append("config endofsim noexit")
if saif_mode == "time":
assert saif_end_time
assert stime
etime = TimeValue(saif_end_time)
find_regs_run_tcl.append("run {end}ns".format(end=(etime.value_in_units("ns") - stime.value_in_units("ns"))))
elif saif_mode == "trigger_raw":
Expand Down
8 changes: 8 additions & 0 deletions hammer/sim/xcelium/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ def generate_saif_tcl_cmd(self) -> str:
saif_args = ""

# Process saif options
saif_start_time: Optional[str] = None
saif_end_time: Optional[str] = None
saif_start_trigger_raw: Optional[str] = None
saif_end_trigger_raw: Optional[str] = None
if saif_opts["mode"] == "time":
saif_start_time = saif_opts["start_time"]
saif_end_time = saif_opts["end_time"]
Expand All @@ -322,12 +326,16 @@ def generate_saif_tcl_cmd(self) -> str:

if saif_opts["mode"] is not None:
if saif_opts["mode"] == "time":
assert saif_start_time
assert saif_end_time
stime = TimeValue(saif_start_time)
etime = TimeValue(saif_end_time)
saif_args = saif_args + f'dumpsaif -output ucli.saif -overwrite -scope {prefix} -start {stime.value_in_units("ns")}ns -stop{etime.value_in_units("ns")}ns'
elif saif_opts["mode"] == "full":
saif_args = saif_args + f"dumpsaif -output ucli.saif -overwrite -scope {prefix}"
elif saif_opts["mode"] == "trigger_raw":
assert saif_start_trigger_raw
assert saif_end_trigger_raw
saif_args = saif_args + f"dumpsaif -output ucli.saif -overwrite -scope {prefix} {saif_start_trigger_raw} {saif_end_trigger_raw}"
return saif_args

Expand Down
6 changes: 3 additions & 3 deletions hammer/tech/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class LibraryFilter(BaseModel):
# Additional filter function to use to exclude possible libraries.
filter_func: Optional[Callable[[Library], bool]] = None
# Sort function to control the order in which outputs are listed
sort_func: Optional[Callable[[Library], Union[Number, str, tuple]]] = None
sort_func: Optional[Callable[[Library], Union[Number, str, tuple, int]]] = None
# List of functions to call on the list-level (the list of elements generated by func) before output and
# post-processing.
extra_post_filter_funcs: List[Callable[[List[str]], List[str]]] = []
Expand Down Expand Up @@ -346,8 +346,8 @@ def __init__(self):
# The technology Python package
self.package: str = ""

# Configuration
self.config: TechJSON = None
# Configuration, since this constructor will never be used, self.config will never seen as None
self.config: TechJSON = None # type: ignore

# Units (converted to Time/CapacitanceValue later)
self.time_unit: Optional[str] = None
Expand Down
2 changes: 2 additions & 0 deletions hammer/tech/stackup.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def quantize_to_width_table(self, width: Decimal, layer: str, logger: Optional[H
Issues a logger warning for the user if the returned width was quantized.
"""
width_table = self.power_strap_width_table
qwidth: Optional[Decimal] = None
if len(width_table) == 0:
qwidth = width
else:
Expand All @@ -264,6 +265,7 @@ def quantize_to_width_table(self, width: Decimal, layer: str, logger: Optional[H
logger.warning("The desired power strap width {dw} on {lay} was quantized down to {fw} based on the technology's width table. Please check your power grid.".format(dw=str(width), lay=layer, fw=str(width_table[i-1])))
qwidth = width_table[i-1]
break
assert qwidth
return qwidth

def get_width_spacing_start_twt(self,
Expand Down
2 changes: 2 additions & 0 deletions hammer/technology/asap7/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def generate_multi_vt_gds(self) -> None:

stdcell_dir = self.get_setting("technology.asap7.stdcell_install_dir")
orig_gds = os.path.join(stdcell_dir, "GDS/asap7sc7p5t_27_R_201211.gds")
cell_list: Optional[List[str]] = None

if self.gds_tool.__name__ == 'gdstk':
# load original GDS
Expand Down Expand Up @@ -140,6 +141,7 @@ def generate_multi_vt_gds(self) -> None:

# Write out cell list for scaling script
with open(os.path.join(self.cache_dir, 'stdcells.txt'), 'w') as f:
assert cell_list
f.writelines('{}\n'.format(cell) for cell in cell_list)

except:
Expand Down
2 changes: 2 additions & 0 deletions hammer/technology/asap7/gds_scale.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# This is called by a tech hook that should be inserted post write_design

import sys, glob, os, re
from typing import Any

def main():
assert len(sys.argv) == 3, 'Must have 2 arguments: 1) Path to list of standard cells, 2) Path to GDS file'
Expand All @@ -26,6 +27,7 @@ def main():
# load the standard cell list
cell_list = [line.rstrip() for line in open(stdcells, 'r')]

gds_lib: Any = None
if gds_tool.__name__ == 'gdstk':
# load original_gds
gds_lib = gds_tool.read_gds(infile=gds_file)
Expand Down
4 changes: 4 additions & 0 deletions hammer/technology/asap7/sram_compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import importlib.resources
from pathlib import Path
from typing import Optional

from hammer.tech import Library, ExtraLibrary
from hammer.vlsi import MMMCCorner, MMMCCornerType, HammerSRAMGeneratorTool, SRAMParameters
Expand All @@ -17,6 +18,8 @@ def version_number(self, version: str) -> int:
# Run generator for a single sram and corner
def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibrary:
tech_cache_dir = os.path.abspath(self.technology.cache_dir)
fam_code: Optional[str] = None
speed_name: Optional[str] = None
if params.family == "1RW" or params.family == "2RW":
fam_code = params.family
else:
Expand Down Expand Up @@ -208,6 +211,7 @@ def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibr
gds_dir = package_dir / "memories/gds"

from hammer.tech import Corner, Supplies, Provide
assert speed_name is not None
lib = ExtraLibrary(prefix=None, library=Library(
name=sram_name,
nldm_liberty_file=f"{nldm_lib_dir}/{nldm_lib_file}",
Expand Down
1 change: 1 addition & 0 deletions hammer/technology/sky130/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pathlib import Path
from typing import NamedTuple, List, Optional, Tuple, Dict, Set, Any
import importlib
import importlib.resources
import json

import hammer.tech
Expand Down
8 changes: 5 additions & 3 deletions hammer/technology/sky130/sram_compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from hammer.tech import Corner, Supplies, Provide
from hammer.vlsi.units import VoltageValue, TemperatureValue
from hammer.tech import Library, ExtraLibrary
from typing import NamedTuple, Dict, Any, List
from typing import NamedTuple, Dict, Any, List, Optional
from abc import ABCMeta, abstractmethod

class SKY130SRAMGenerator(HammerSRAMGeneratorTool):
Expand All @@ -19,7 +19,7 @@ def version_number(self, version: str) -> int:
# Run generator for a single sram and corner
def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibrary:
cache_dir = os.path.abspath(self.technology.cache_dir)

speed_name: Optional[str] = None
#TODO: this is really an abuse of the corner stuff
if corner.type == MMMCCornerType.Setup:
speed_name = "slow"
Expand Down Expand Up @@ -54,6 +54,7 @@ def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibr
base_dir=self.get_setting('technology.sky130.sram22_sky130_macros')

found = False
lib_path: Optional[str] = None
for fidelity in ["rcc", "rc", "c"]:
lib_path="{b}/{n}/{n}_{c}.{f}.lib".format(b=base_dir,n=sram_name,c=corner_str, f=fidelity)
if os.path.exists(lib_path):
Expand All @@ -64,7 +65,7 @@ def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibr

if not found:
self.logger.error(f"SKY130 {params.name} SRAM cache does not support corner {corner_str}")

assert speed_name
return ExtraLibrary(prefix=None, library=Library(
name=sram_name,
nldm_liberty_file=lib_path,
Expand Down Expand Up @@ -104,6 +105,7 @@ def generate_sram(self, params: SRAMParameters, corner: MMMCCorner) -> ExtraLibr
self.setup_openram_lef(sram_name)
self.setup_openram_verilog(sram_name)
# self.setup_sram_lib(sram_name)
assert speed_name
return ExtraLibrary(prefix=None, library=Library(
name=sram_name,
nldm_liberty_file="{b}/{n}/{n}_{c}.lib".format(b=base_dir,n=sram_name,c=corner_str),
Expand Down
4 changes: 2 additions & 2 deletions hammer/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@ def compare_types_internal(a: Any, b: Any) -> bool:
elif a == dict and b == typing.Dict:
return True
elif is_union(a) and is_union(b):
if len(a.__args__) == len(b.__args__):
for ai, bi in list(zip(a.__args__, b.__args__)):
if len(a.__args__) == len(b.__args__): # type: ignore
for ai, bi in list(zip(a.__args__, b.__args__)): # type: ignore
if not compare_types(ai, bi):
return False
return True
Expand Down
1 change: 1 addition & 0 deletions hammer/vlsi/cli_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ def __init__(self) -> None:
self.timing_rundir = "" # type: Optional[str]
self.pcb_rundir = "" # type: Optional[str]

self.synthesis_action: CLIActionConfigType
# If a subclass has defined these, don't clobber them in init
# since the subclass still uses this init function.
if hasattr(self, "sram_generator_action"):
Expand Down
4 changes: 1 addition & 3 deletions hammer/vlsi/hammer_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,6 @@ def run_dir(self) -> str:
"""
try:
return self._rundir
except AttributeError:
return self._rundir
except AttributeError:
harrisonliew marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("Internal error: run dir location not set by hammer-vlsi")

Expand Down Expand Up @@ -1329,7 +1327,7 @@ def get_macro_wh(macro: Optional[str]) -> Tuple[Decimal, Decimal]:

p_nets = self.get_all_power_nets() #type: List[Supply]
g_nets = self.get_all_ground_nets() #type: List[Supply]
for b in bumps.assignments: # type: BumpAssignment
for b in bumps.assignments:
bump_type = 'signal'
if b.no_connect:
bump_type = 'nc'
Expand Down
Loading
Loading