From 5c4192ef4aae173e9d4651d7840885cb7d894ee7 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson <oscar.gustafsson@gmail.com>
Date: Fri, 19 Apr 2024 14:45:34 +0200
Subject: [PATCH] Improve typing (and some docs)

---
 b_asic/architecture.py              | 36 +++++++++++++----------------
 b_asic/codegen/vhdl/architecture.py | 11 +++++----
 b_asic/process.py                   |  9 ++++----
 b_asic/schedule.py                  | 14 ++++-------
 b_asic/scheduler_gui/main_window.py |  2 +-
 pyproject.toml                      |  2 +-
 6 files changed, 34 insertions(+), 40 deletions(-)

diff --git a/b_asic/architecture.py b/b_asic/architecture.py
index f919482a..75e5d971 100644
--- a/b_asic/architecture.py
+++ b/b_asic/architecture.py
@@ -305,7 +305,7 @@ class Resource(HardwareBlock):
         return self._collection
 
     @property
-    def operation_type(self) -> Union[Type[MemoryProcess], Type[OperatorProcess]]:
+    def operation_type(self) -> Union[Type[MemoryProcess], Type[Operation]]:
         raise NotImplementedError("ABC Resource does not implement operation_type")
 
     def add_process(self, proc: Process, assign=False):
@@ -621,12 +621,8 @@ of :class:`~b_asic.architecture.ProcessingElement`
         return schedule_times.pop()
 
     def _build_dicts(self) -> None:
-        self._variable_input_port_to_resource: DefaultDict[
-            InputPort, Set[Tuple[Resource, int]]
-        ] = defaultdict(set)
-        self._variable_outport_to_resource: DefaultDict[
-            OutputPort, Set[Tuple[Resource, int]]
-        ] = defaultdict(set)
+        self._variable_input_port_to_resource = defaultdict(set)
+        self._variable_outport_to_resource = defaultdict(set)
         self._operation_input_port_to_resource = {}
         self._operation_outport_to_resource = {}
         for pe in self.processing_elements:
@@ -677,8 +673,8 @@ of :class:`~b_asic.architecture.ProcessingElement`
                 memory_write_ports.add(mv.write_port)
                 memory_read_ports.update(mv.read_ports)
 
-        pe_input_ports = set()
-        pe_output_ports = set()
+        pe_input_ports: Set[InputPort] = set()
+        pe_output_ports: Set[OutputPort] = set()
         for pe in self.processing_elements:
             for operator in pe.processes:
                 pe_input_ports.update(operator.operation.inputs)
@@ -806,9 +802,9 @@ of :class:`~b_asic.architecture.ProcessingElement`
             raise ValueError("Resource must be empty")
 
         if resource in self.memories:
-            self.memories.remove(resource)
+            self.memories.remove(cast(Memory, resource))
         elif resource in self.processing_elements:
-            self.processing_elements.remove(resource)
+            self.processing_elements.remove(cast(ProcessingElement, resource))
         else:
             raise ValueError('Resource not in architecture')
 
@@ -838,10 +834,10 @@ of :class:`~b_asic.architecture.ProcessingElement`
         assign: bool = False,
     ) -> None:
         """
-        Move a :class:`b_asic.process.Process` from one :class:`Resource`  to another.
+        Move a :class:`~b_asic.process.Process` from one :class:`Resource`  to another.
 
         Both the resource moved from and will become unassigned after a process has been
-        moved, unless *assign* is set to True.
+        moved, unless *assign* is True.
 
         Parameters
         ----------
@@ -1033,25 +1029,25 @@ of :class:`~b_asic.architecture.ProcessingElement`
 
         destination_list = {k: list(v) for k, v in destination_edges.items()}
         if multiplexers:
-            for destination, source_list in destination_list.items():
+            for destination_str, source_list in destination_list.items():
                 if len(source_list) > 1:
                     # Create GraphViz struct for multiplexer
-                    inputs = [f"in{i}" for i in range(len(source_list))]
+                    input_strings = [f"in{i}" for i in range(len(source_list))]
                     ret = (
                         '<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"'
                         ' CELLPADDING="4">'
                     )
                     in_strs = [
                         f'<TD COLSPAN="1" PORT="{in_str}">{in_str}</TD>'
-                        for in_str in inputs
+                        for in_str in input_strings
                     ]
                     ret += f"<TR>{''.join(in_strs)}</TR>"
-                    name = f"{destination.replace(':', '_')}_mux"
+                    name = f"{destination_str.replace(':', '_')}_mux"
                     ret += (
-                        f'<TR><TD COLSPAN="{len(inputs)}"'
+                        f'<TR><TD COLSPAN="{len(input_strings)}"'
                         f' PORT="{name}"><B>{name}</B></TD></TR>'
                     )
-                    ret += f'<TR><TD COLSPAN="{len(inputs)}" PORT="out0">out0</TD></TR>'
+                    ret += f'<TR><TD COLSPAN="{len(input_strings)}" PORT="out0">out0</TD></TR>'
                     dg.node(
                         name,
                         ret + "</TABLE>>",
@@ -1060,7 +1056,7 @@ of :class:`~b_asic.architecture.ProcessingElement`
                         fontname='Times New Roman',
                     )
                     # Add edge from mux output to resource input
-                    dg.edge(f"{name}:out0", destination)
+                    dg.edge(f"{name}:out0", destination_str)
 
         # Add edges to graph
         for src_str, destination_counts in edges.items():
diff --git a/b_asic/codegen/vhdl/architecture.py b/b_asic/codegen/vhdl/architecture.py
index 4b708f08..439ae4ba 100644
--- a/b_asic/codegen/vhdl/architecture.py
+++ b/b_asic/codegen/vhdl/architecture.py
@@ -571,13 +571,14 @@ def register_based_storage(
     reg_cnt = len(forward_backward_table[0].regs)
 
     # Set of the register indices to output from
-    output_regs = {entry.outputs_from for entry in forward_backward_table.table}
-    if None in output_regs:
-        output_regs.remove(None)
-    output_regs = cast(Set[int], output_regs)
+    output_regs = {
+        entry.outputs_from
+        for entry in forward_backward_table.table
+        if entry.outputs_from is not None
+    }
 
     # Table with mapping: register to output multiplexer index
-    output_mux_table = {reg: i for i, reg in enumerate(output_regs)}
+    output_mux_table: Dict[int, int] = {reg: i for i, reg in enumerate(output_regs)}
 
     # Back-edge register indices
     back_edges: Set[Tuple[int, int]] = {
diff --git a/b_asic/process.py b/b_asic/process.py
index 833a12a5..74ca40b4 100644
--- a/b_asic/process.py
+++ b/b_asic/process.py
@@ -146,8 +146,8 @@ class MemoryProcess(Process):
         )
 
     @property
-    def read_times(self) -> List[int]:
-        return list(self.start_time + read for read in self._life_times)
+    def read_times(self) -> Tuple[int, ...]:
+        return tuple(self.start_time + read for read in self._life_times)
 
     @property
     def life_times(self) -> List[int]:
@@ -170,8 +170,9 @@ class MemoryProcess(Process):
         length: int = 0,
     ) -> Tuple[Optional["MemoryProcess"], Optional["MemoryProcess"]]:
         """
-        Split this :class:`MemoryProcess` into two new :class:`MemoryProcess` objects,
-        based on lifetimes of the read accesses.
+        Split this :class:`MemoryProcess` into two new :class:`MemoryProcess` objects.
+
+        This is based on the lifetimes of the read accesses.
 
         Parameters
         ----------
diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 9cb4132d..8365d194 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -7,7 +7,7 @@ Contains the schedule class for scheduling operations in an SFG.
 import io
 import sys
 from collections import defaultdict
-from typing import Dict, List, Optional, Sequence, Tuple, Union, cast
+from typing import Dict, List, Optional, Sequence, Tuple, cast
 
 import matplotlib.pyplot as plt
 import numpy as np
@@ -38,15 +38,11 @@ from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
 
 # Need RGB from 0 to 1
-_EXECUTION_TIME_COLOR: Union[
-    Tuple[float, float, float], Tuple[float, float, float, float]
-] = tuple(float(c / 255) for c in EXECUTION_TIME_COLOR)
-_LATENCY_COLOR: Union[Tuple[float, float, float], Tuple[float, float, float, float]] = (
-    tuple(float(c / 255) for c in LATENCY_COLOR)
-)
-_SIGNAL_COLOR: Union[Tuple[float, float, float], Tuple[float, float, float, float]] = (
-    tuple(float(c / 255) for c in SIGNAL_COLOR)
+_EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple(
+    float(c / 255) for c in EXECUTION_TIME_COLOR
 )
+_LATENCY_COLOR: Tuple[float, ...] = tuple(float(c / 255) for c in LATENCY_COLOR)
+_SIGNAL_COLOR: Tuple[float, ...] = tuple(float(c / 255) for c in SIGNAL_COLOR)
 
 
 def _laps_default():
diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index d2ef99b6..b331abcc 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -1006,7 +1006,7 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow):
             self.actionToggle_full_screen.setIcon(get_icon('full-screen-exit'))
 
 
-def start_scheduler(schedule: Optional[Schedule] = None) -> Schedule:
+def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]:
     """
     Start scheduler GUI.
 
diff --git a/pyproject.toml b/pyproject.toml
index 558e8e9f..f5cc2814 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -76,7 +76,7 @@ ignore_missing_imports = true
 precision = 2
 
 [tool.ruff]
-ignore = ["F403"]
+lint.ignore = ["F403"]
 
 [tool.typos]
 default.extend-identifiers = { addd0 = "addd0", inout = "inout", ArChItEctUrE = "ArChItEctUrE" }
-- 
GitLab