From a6de33c18946f4ff01b3ede554809fb3c0285683 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Tue, 18 Mar 2025 16:22:00 +0100
Subject: [PATCH] added comprehensions ruff rule and addressed issues

---
 b_asic/GUI/drag_button.py              |  7 +------
 b_asic/GUI/main_window.py              |  4 ++--
 b_asic/core_operations.py              |  6 +++---
 b_asic/operation.py                    |  2 +-
 b_asic/process.py                      |  8 ++++----
 b_asic/resources.py                    |  4 ++--
 b_asic/scheduler_gui/main_window.py    |  8 ++++----
 b_asic/scheduler_gui/scheduler_item.py |  2 +-
 b_asic/signal_flow_graph.py            |  3 ++-
 b_asic/special_operations.py           |  4 ++--
 docs_sphinx/conf.py                    |  2 +-
 pyproject.toml                         |  2 +-
 test/unit/test_list_schedulers.py      |  2 +-
 test/unit/test_sfg.py                  | 12 ++++++------
 test/unit/test_sfg_generators.py       |  4 ++--
 15 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/b_asic/GUI/drag_button.py b/b_asic/GUI/drag_button.py
index 18308ef7..e628f2a2 100644
--- a/b_asic/GUI/drag_button.py
+++ b/b_asic/GUI/drag_button.py
@@ -222,12 +222,7 @@ class DragButton(QPushButton):
 
         _signals = []
         for signal, ports in self._window._arrow_ports.items():
-            if any(
-                map(
-                    lambda port: set(port).intersection(set(self._ports)),
-                    ports,
-                )
-            ):
+            if any(set(port).intersection(set(self._ports)) for port in ports):
                 self._window._logger.info(
                     "Removed signal with name: %s to/from operation: %s."
                     % (signal.signal.name, self.operation.name)
diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py
index 1a4419c1..24e48ecf 100644
--- a/b_asic/GUI/main_window.py
+++ b/b_asic/GUI/main_window.py
@@ -903,8 +903,8 @@ class SFGMainWindow(QMainWindow):
 
     def _simulate_sfg(self) -> None:
         """Callback for simulating SFGs in separate threads."""
-        self._thread = dict()
-        self._sim_worker = dict()
+        self._thread = {}
+        self._sim_worker = {}
         for sfg, properties in self._simulation_dialog._properties.items():
             self._logger.info("Simulating SFG with name: %s" % str(sfg.name))
             self._sim_worker[sfg] = SimulationWorker(sfg, properties)
diff --git a/b_asic/core_operations.py b/b_asic/core_operations.py
index a879edec..30375a2f 100644
--- a/b_asic/core_operations.py
+++ b/b_asic/core_operations.py
@@ -100,7 +100,7 @@ class Constant(AbstractOperation):
 
     def get_input_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
-        return tuple()
+        return ()
 
     def get_output_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
@@ -1724,7 +1724,7 @@ class DontCare(AbstractOperation):
 
     def get_input_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
-        return tuple()
+        return ()
 
     def get_output_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
@@ -1791,4 +1791,4 @@ class Sink(AbstractOperation):
 
     def get_output_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
-        return tuple()
+        return ()
diff --git a/b_asic/operation.py b/b_asic/operation.py
index 2a1be12a..89977686 100644
--- a/b_asic/operation.py
+++ b/b_asic/operation.py
@@ -985,7 +985,7 @@ class AbstractOperation(Operation, AbstractGraphComponent):
         # Always a rectangle, but easier if coordinates are returned
         execution_time = self._execution_time  # Copy for type checking
         if execution_time is None:
-            return tuple()
+            return ()
         return (
             (0, 0),
             (0, 1),
diff --git a/b_asic/process.py b/b_asic/process.py
index d165a13e..be4ccbe2 100644
--- a/b_asic/process.py
+++ b/b_asic/process.py
@@ -198,8 +198,8 @@ class MemoryProcess(Process):
         reads exists), and vice-versa for the other tuple element.
         """
         reads = self.reads
-        short_reads = {k: v for k, v in filter(lambda t: t[1] <= length, reads.items())}
-        long_reads = {k: v for k, v in filter(lambda t: t[1] > length, reads.items())}
+        short_reads = dict(filter(lambda t: t[1] <= length, reads.items()))
+        long_reads = dict(filter(lambda t: t[1] > length, reads.items()))
         short_process = None
         long_process = None
         if short_reads:
@@ -319,7 +319,7 @@ class MemoryVariable(MemoryProcess):
         return self._write_port
 
     def __repr__(self) -> str:
-        reads = {k: v for k, v in zip(self._read_ports, self._life_times, strict=True)}
+        reads = dict(zip(self._read_ports, self._life_times, strict=True))
         return (
             f"MemoryVariable({self.start_time}, {self.write_port},"
             f" {reads!r}, {self.name!r})"
@@ -413,7 +413,7 @@ class PlainMemoryVariable(MemoryProcess):
         return self._write_port
 
     def __repr__(self) -> str:
-        reads = {k: v for k, v in zip(self._read_ports, self._life_times, strict=True)}
+        reads = dict(zip(self._read_ports, self._life_times, strict=True))
         return (
             f"PlainMemoryVariable({self.start_time}, {self.write_port},"
             f" {reads!r}, {self.name!r})"
diff --git a/b_asic/resources.py b/b_asic/resources.py
index 36e2cec9..9f4015ae 100644
--- a/b_asic/resources.py
+++ b/b_asic/resources.py
@@ -1172,7 +1172,7 @@ class ProcessCollection:
                     f"{process} has execution time greater than the schedule time"
                 )
 
-        cell_assignment: dict[int, ProcessCollection] = dict()
+        cell_assignment: dict[int, ProcessCollection] = {}
         exclusion_graph = self.create_exclusion_graph_from_execution_time()
         if coloring is None:
             coloring = nx.coloring.greedy_color(
@@ -1599,7 +1599,7 @@ class ProcessCollection:
     def total_port_accesses(self) -> dict[int, int]:
         accesses = sum(
             (
-                list(read_time % self.schedule_time for read_time in process.read_times)
+                [read_time % self.schedule_time for read_time in process.read_times]
                 for process in self._collection
             ),
             [process.start_time % self.schedule_time for process in self._collection],
diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index b2950268..8a86fac7 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -115,8 +115,8 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow):
     _splitter_pos: int
     _splitter_min: int
     _zoom: float
-    _color_per_type: dict[str, QColor] = dict()
-    _converted_color_per_type: dict[str, str] = dict()
+    _color_per_type: dict[str, QColor] = {}
+    _converted_color_per_type: dict[str, str] = {}
 
     def __init__(self):
         """Initialize Scheduler-GUI."""
@@ -137,7 +137,7 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow):
         self._execution_time_plot_dialogs = defaultdict(lambda: None)
         self._ports_accesses_for_storage = None
         self._color_changed_per_type = False
-        self._changed_operation_colors: dict[str, QColor] = dict()
+        self._changed_operation_colors: dict[str, QColor] = {}
 
         # Recent files
         self._max_recent_files = 4
@@ -376,7 +376,7 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow):
             return
 
         if len(schedule_obj_list) == 1:
-            schedule = [val for val in schedule_obj_list.values()][0]
+            schedule = list(schedule_obj_list.values())[0]
         else:
             ret_tuple = QInputDialog.getItem(
                 self,
diff --git a/b_asic/scheduler_gui/scheduler_item.py b/b_asic/scheduler_gui/scheduler_item.py
index 43091545..21df470c 100644
--- a/b_asic/scheduler_gui/scheduler_item.py
+++ b/b_asic/scheduler_gui/scheduler_item.py
@@ -306,7 +306,7 @@ class SchedulerItem(SchedulerEvent, QGraphicsItemGroup):
 
     @property
     def components(self) -> list[OperationItem]:
-        return list(component for component in self._operation_items.values())
+        return list(self._operation_items.values())
 
     @property
     def event_items(self) -> list[QGraphicsItem]:
diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py
index de2a9db8..0067a44e 100644
--- a/b_asic/signal_flow_graph.py
+++ b/b_asic/signal_flow_graph.py
@@ -587,7 +587,8 @@ class SFG(AbstractOperation):
             for comp in self._components_dfs_order
             if isinstance(comp, component_type)
         ]
-        return sorted(list(set(components)), key=lambda c: c.name or c.graph_id)
+        components = list(set(components))  # ensure no redundant elements
+        return sorted(components, key=lambda c: c.name or c.graph_id)
 
     def find_by_id(self, graph_id: GraphID) -> GraphComponent | None:
         """
diff --git a/b_asic/special_operations.py b/b_asic/special_operations.py
index dbffb2af..ca115908 100644
--- a/b_asic/special_operations.py
+++ b/b_asic/special_operations.py
@@ -90,7 +90,7 @@ class Input(AbstractOperation):
 
     def get_input_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
-        return tuple()
+        return ()
 
     def get_output_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
@@ -153,7 +153,7 @@ class Output(AbstractOperation):
 
     def get_output_coordinates(self) -> tuple[tuple[float, float], ...]:
         # doc-string inherited
-        return tuple()
+        return ()
 
     @property
     def latency(self) -> int:
diff --git a/docs_sphinx/conf.py b/docs_sphinx/conf.py
index 1822a3ec..0212d854 100644
--- a/docs_sphinx/conf.py
+++ b/docs_sphinx/conf.py
@@ -56,7 +56,7 @@ numpydoc_validation_checks = {
     "RT03",
 }
 
-inheritance_node_attrs = dict(fontsize=16)
+inheritance_node_attrs = {"fontsize": 16}
 
 graphviz_dot = shutil.which("dot")
 
diff --git a/pyproject.toml b/pyproject.toml
index 3cfd42e4..1e7aa180 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -100,7 +100,7 @@ precision = 2
 exclude = ["examples"]
 
 [tool.ruff.lint]
-select = ["E4", "E7", "E9", "F", "SIM", "B", "NPY"]
+select = ["E4", "E7", "E9", "F", "SIM", "B", "NPY", "C4"]
 ignore = ["F403", "B008", "B021", "B006"]
 
 [tool.typos]
diff --git a/test/unit/test_list_schedulers.py b/test/unit/test_list_schedulers.py
index b67147d9..b9d397b8 100644
--- a/test/unit/test_list_schedulers.py
+++ b/test/unit/test_list_schedulers.py
@@ -1663,7 +1663,7 @@ class TestHybridScheduler:
             "rec2": 36,
         }
 
-        assert all([val == 0 for val in schedule.laps.values()])
+        assert all(val == 0 for val in schedule.laps.values())
         _validate_recreated_sfg_ldlt_matrix_inverse(schedule, 3)
 
     def test_latency_offsets_cyclic(self):
diff --git a/test/unit/test_sfg.py b/test/unit/test_sfg.py
index 7cd54fc4..954c0c82 100644
--- a/test/unit/test_sfg.py
+++ b/test/unit/test_sfg.py
@@ -359,8 +359,8 @@ class TestInsertComponent:
         _sfg = sfg.insert_operation(sqrt, sfg.find_by_name("constant4")[0].graph_id)
         assert _sfg.evaluate() != sfg.evaluate()
 
-        assert any([isinstance(comp, SquareRoot) for comp in _sfg.operations])
-        assert not any([isinstance(comp, SquareRoot) for comp in sfg.operations])
+        assert any(isinstance(comp, SquareRoot) for comp in _sfg.operations)
+        assert not any(isinstance(comp, SquareRoot) for comp in sfg.operations)
 
         assert not isinstance(
             sfg.find_by_name("constant4")[0].output(0).signals[0].destination.operation,
@@ -1664,8 +1664,8 @@ class TestInsertComponentAfter:
         )
         assert _sfg.evaluate() != sfg.evaluate()
 
-        assert any([isinstance(comp, SquareRoot) for comp in _sfg.operations])
-        assert not any([isinstance(comp, SquareRoot) for comp in sfg.operations])
+        assert any(isinstance(comp, SquareRoot) for comp in _sfg.operations)
+        assert not any(isinstance(comp, SquareRoot) for comp in sfg.operations)
 
         assert not isinstance(
             sfg.find_by_name("constant4")[0].output(0).signals[0].destination.operation,
@@ -1716,8 +1716,8 @@ class TestInsertComponentBefore:
         )
         assert _sfg.evaluate() != sfg.evaluate()
 
-        assert any([isinstance(comp, SquareRoot) for comp in _sfg.operations])
-        assert not any([isinstance(comp, SquareRoot) for comp in sfg.operations])
+        assert any(isinstance(comp, SquareRoot) for comp in _sfg.operations)
+        assert not any(isinstance(comp, SquareRoot) for comp in sfg.operations)
 
         assert not isinstance(
             sfg.find_by_name("bfly1")[0].input(0).signals[0].source.operation,
diff --git a/test/unit/test_sfg_generators.py b/test/unit/test_sfg_generators.py
index f427259e..569528b8 100644
--- a/test/unit/test_sfg_generators.py
+++ b/test/unit/test_sfg_generators.py
@@ -293,12 +293,12 @@ class TestDirectFormIIRType1:
         with pytest.raises(
             ValueError, match="Size of coefficient lists a and b are not the same."
         ):
-            direct_form_1_iir([i for i in range(10)], [i for i in range(11)])
+            direct_form_1_iir(list(range(10)), list(range(11)))
 
         with pytest.raises(
             ValueError, match="Size of coefficient lists a and b are not the same."
         ):
-            direct_form_1_iir([i for i in range(10)], [i for i in range(11)])
+            direct_form_1_iir(list(range(10)), list(range(11)))
 
     def test_a0_not_1(self):
         with pytest.raises(ValueError, match=r"The value of a\[0] must be 1\."):
-- 
GitLab