From eeb4c50880c599efb35e477b26123b2e635d4c4e Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:46:41 +0000 Subject: [PATCH 01/34] Agustin's suggested Protocol class --- hugr-py/src/hugr/hugr/pass.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 hugr-py/src/hugr/hugr/pass.py diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py new file mode 100644 index 0000000000..b9d0ec67ff --- /dev/null +++ b/hugr-py/src/hugr/hugr/pass.py @@ -0,0 +1,16 @@ +from typing import Protocol, Self +from hugr.hugr.base import Hugr + + +class ComposablePass(Protocol): + def __call__(self, hugr: Hugr) -> None: ... + + def then(self, other: Self) -> Self: ... + + def with_entrypoint(self) -> Self: ... + + @property + def is_global(self) -> bool: ... + + @property + def is_recursive(self) -> bool: ... From c5cf1d7f6657caaf76b7b46e7210cd7cb19b532d Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:50:29 +0000 Subject: [PATCH 02/34] minor fixes --- hugr-py/src/hugr/hugr/pass.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index b9d0ec67ff..82d419827a 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -1,13 +1,19 @@ +"""A Protocol for a composable pass.""" + from typing import Protocol, Self + from hugr.hugr.base import Hugr +from hugr.node_port import Node class ComposablePass(Protocol): + """A Protocol which represents a composable Hugr transformation.""" + def __call__(self, hugr: Hugr) -> None: ... def then(self, other: Self) -> Self: ... - def with_entrypoint(self) -> Self: ... + def with_entrypoint(self, node: Node) -> Self: ... @property def is_global(self) -> bool: ... From 8a3d6baa08085298d6aff32b3a16ff05b5d53af7 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:57:31 +0000 Subject: [PATCH 03/34] more methods --- hugr-py/src/hugr/hugr/pass.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index 82d419827a..14c8e74705 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -4,6 +4,7 @@ from hugr.hugr.base import Hugr from hugr.node_port import Node +from hugr.ops import Op class ComposablePass(Protocol): @@ -15,6 +16,14 @@ def then(self, other: Self) -> Self: ... def with_entrypoint(self, node: Node) -> Self: ... + @classmethod + def from_dict(cls, dictionary: dict) -> Self: ... + + def to_dict(self) -> dict: ... + + @property + def supported_ops(self) -> set[Op]: ... + @property def is_global(self) -> bool: ... From 7b58c056a62c79fa8d7ae14c76cef00748a920a6 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:33:50 +0000 Subject: [PATCH 04/34] import Self from typing_extensions --- hugr-py/src/hugr/hugr/pass.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index 14c8e74705..c26cd01344 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -1,6 +1,8 @@ """A Protocol for a composable pass.""" -from typing import Protocol, Self +from typing import Protocol + +from typing_extensions import Self from hugr.hugr.base import Hugr from hugr.node_port import Node From 5e31a3d785f771ebf80e832364dbe22761c9cedd Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:40:53 +0000 Subject: [PATCH 05/34] fix import --- hugr-py/src/hugr/hugr/pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index c26cd01344..ac9c594c74 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -5,7 +5,7 @@ from typing_extensions import Self from hugr.hugr.base import Hugr -from hugr.node_port import Node +from hugr.hugr.node_port import Node from hugr.ops import Op From c52de850fcc60c9a64b295d91a4b53f501654a44 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:17:14 +0000 Subject: [PATCH 06/34] remove to_dict and from_dict methods as well as supported Ops --- hugr-py/src/hugr/hugr/pass.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index ac9c594c74..ca7907d514 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -18,14 +18,6 @@ def then(self, other: Self) -> Self: ... def with_entrypoint(self, node: Node) -> Self: ... - @classmethod - def from_dict(cls, dictionary: dict) -> Self: ... - - def to_dict(self) -> dict: ... - - @property - def supported_ops(self) -> set[Op]: ... - @property def is_global(self) -> bool: ... From 6d7afc2b8f88daea25d3d43cffb41616f53a3b54 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:17:48 +0000 Subject: [PATCH 07/34] remove unused import --- hugr-py/src/hugr/hugr/pass.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index ca7907d514..a6afd50aae 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -6,7 +6,6 @@ from hugr.hugr.base import Hugr from hugr.hugr.node_port import Node -from hugr.ops import Op class ComposablePass(Protocol): From 89fabf038bfe97c6c16d4208f2a42266fb47aa48 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:26:09 +0000 Subject: [PATCH 08/34] node -> entrypoint --- hugr-py/src/hugr/hugr/pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/pass.py index a6afd50aae..0ad945996b 100644 --- a/hugr-py/src/hugr/hugr/pass.py +++ b/hugr-py/src/hugr/hugr/pass.py @@ -15,7 +15,7 @@ def __call__(self, hugr: Hugr) -> None: ... def then(self, other: Self) -> Self: ... - def with_entrypoint(self, node: Node) -> Self: ... + def with_entrypoint(self, entrypoint: Node) -> Self: ... @property def is_global(self) -> bool: ... From 4878d5f72059541f7f75720f28c2201a0ccd0118 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:52:08 +0000 Subject: [PATCH 09/34] rename and update __init__.py --- hugr-py/src/hugr/hugr/__init__.py | 10 ++++++---- hugr-py/src/hugr/hugr/{pass.py => composable_pass.py} | 0 2 files changed, 6 insertions(+), 4 deletions(-) rename hugr-py/src/hugr/hugr/{pass.py => composable_pass.py} (100%) diff --git a/hugr-py/src/hugr/hugr/__init__.py b/hugr-py/src/hugr/hugr/__init__.py index 3cbc426d7c..ce4113aead 100644 --- a/hugr-py/src/hugr/hugr/__init__.py +++ b/hugr-py/src/hugr/hugr/__init__.py @@ -1,6 +1,7 @@ """The main HUGR structure.""" from .base import Hugr, NodeData +from .composable_pass import ComposablePass from .node_port import ( Direction, InPort, @@ -10,11 +11,12 @@ ) __all__ = [ - "Hugr", - "NodeData", + "ComposablePass", "Direction", + "Hugr", "InPort", - "Wire", - "OutPort", "Node", + "NodeData", + "OutPort", + "Wire", ] diff --git a/hugr-py/src/hugr/hugr/pass.py b/hugr-py/src/hugr/hugr/composable_pass.py similarity index 100% rename from hugr-py/src/hugr/hugr/pass.py rename to hugr-py/src/hugr/hugr/composable_pass.py From 954730f1b3984dd497fcab4db3591d164db5714c Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:26:16 +0000 Subject: [PATCH 10/34] make a passes module --- hugr-py/src/hugr/build/__init__.py | 16 +++++++++------- .../{hugr => build/passes}/composable_pass.py | 0 hugr-py/src/hugr/hugr/__init__.py | 2 -- 3 files changed, 9 insertions(+), 9 deletions(-) rename hugr-py/src/hugr/{hugr => build/passes}/composable_pass.py (100%) diff --git a/hugr-py/src/hugr/build/__init__.py b/hugr-py/src/hugr/build/__init__.py index def20437fc..3111294989 100644 --- a/hugr-py/src/hugr/build/__init__.py +++ b/hugr-py/src/hugr/build/__init__.py @@ -5,20 +5,22 @@ from .cond_loop import Case, Conditional, If, TailLoop from .dfg import DefinitionBuilder, DfBase, Dfg, Function from .function import Module +from .passes.composable_pass import ComposablePass from .tracked_dfg import TrackedDfg __all__ = [ - "ParentBuilder", - "Cfg", "Block", "Case", - "If", + "Cfg", + "ComposablePass", "Conditional", - "TailLoop", + "DefinitionBuilder", + "DfBase", + "Dfg", "Function", + "If", "Module", + "ParentBuilder", + "TailLoop", "TrackedDfg", - "Dfg", - "DefinitionBuilder", - "DfBase", ] diff --git a/hugr-py/src/hugr/hugr/composable_pass.py b/hugr-py/src/hugr/build/passes/composable_pass.py similarity index 100% rename from hugr-py/src/hugr/hugr/composable_pass.py rename to hugr-py/src/hugr/build/passes/composable_pass.py diff --git a/hugr-py/src/hugr/hugr/__init__.py b/hugr-py/src/hugr/hugr/__init__.py index ce4113aead..940f467333 100644 --- a/hugr-py/src/hugr/hugr/__init__.py +++ b/hugr-py/src/hugr/hugr/__init__.py @@ -1,7 +1,6 @@ """The main HUGR structure.""" from .base import Hugr, NodeData -from .composable_pass import ComposablePass from .node_port import ( Direction, InPort, @@ -11,7 +10,6 @@ ) __all__ = [ - "ComposablePass", "Direction", "Hugr", "InPort", From 448b5cfe97ae0c1f88ea5b5e35e983529a40e56b Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:30:10 +0000 Subject: [PATCH 11/34] move passes into hugr root --- hugr-py/src/hugr/{build => }/passes/composable_pass.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hugr-py/src/hugr/{build => }/passes/composable_pass.py (100%) diff --git a/hugr-py/src/hugr/build/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py similarity index 100% rename from hugr-py/src/hugr/build/passes/composable_pass.py rename to hugr-py/src/hugr/passes/composable_pass.py From 17d1dc8b45d656258706f6dda373edcd9cee2556 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:30:41 +0000 Subject: [PATCH 12/34] remove from build --- hugr-py/src/hugr/build/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/hugr-py/src/hugr/build/__init__.py b/hugr-py/src/hugr/build/__init__.py index 3111294989..8720e94f94 100644 --- a/hugr-py/src/hugr/build/__init__.py +++ b/hugr-py/src/hugr/build/__init__.py @@ -5,14 +5,12 @@ from .cond_loop import Case, Conditional, If, TailLoop from .dfg import DefinitionBuilder, DfBase, Dfg, Function from .function import Module -from .passes.composable_pass import ComposablePass from .tracked_dfg import TrackedDfg __all__ = [ "Block", "Case", "Cfg", - "ComposablePass", "Conditional", "DefinitionBuilder", "DfBase", From b6fa9a58eacc8bc1c81617dcb9a7bde51cfeaf1e Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:32:31 +0000 Subject: [PATCH 13/34] add __init__.py for passes --- hugr-py/src/hugr/passes/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 hugr-py/src/hugr/passes/__init__.py diff --git a/hugr-py/src/hugr/passes/__init__.py b/hugr-py/src/hugr/passes/__init__.py new file mode 100644 index 0000000000..8a34628c1d --- /dev/null +++ b/hugr-py/src/hugr/passes/__init__.py @@ -0,0 +1 @@ +"""A hugr-py passes module for hugr transformations.""" From cc9c1518983f0d2022563c08534d88b826445f8f Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:34:35 +0000 Subject: [PATCH 14/34] undo init changes --- hugr-py/src/hugr/build/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hugr-py/src/hugr/build/__init__.py b/hugr-py/src/hugr/build/__init__.py index 8720e94f94..def20437fc 100644 --- a/hugr-py/src/hugr/build/__init__.py +++ b/hugr-py/src/hugr/build/__init__.py @@ -8,17 +8,17 @@ from .tracked_dfg import TrackedDfg __all__ = [ + "ParentBuilder", + "Cfg", "Block", "Case", - "Cfg", + "If", "Conditional", - "DefinitionBuilder", - "DfBase", - "Dfg", + "TailLoop", "Function", - "If", "Module", - "ParentBuilder", - "TailLoop", "TrackedDfg", + "Dfg", + "DefinitionBuilder", + "DfBase", ] From 2d10e874381a2c767f65affa92c8e5b35d6d3f26 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:35:28 +0000 Subject: [PATCH 15/34] update __all__ --- hugr-py/src/hugr/hugr/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hugr-py/src/hugr/hugr/__init__.py b/hugr-py/src/hugr/hugr/__init__.py index 940f467333..3e2011e610 100644 --- a/hugr-py/src/hugr/hugr/__init__.py +++ b/hugr-py/src/hugr/hugr/__init__.py @@ -10,9 +10,13 @@ ) __all__ = [ + "Hugr", + "NodeData", "Direction", "Hugr", "InPort", + "Wire", + "OutPort", "Node", "NodeData", "OutPort", From 45bd86aefe91d7426fb34026b08faa6b29d384db Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:36:28 +0000 Subject: [PATCH 16/34] fix __all__ again --- hugr-py/src/hugr/hugr/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hugr-py/src/hugr/hugr/__init__.py b/hugr-py/src/hugr/hugr/__init__.py index 3e2011e610..3cbc426d7c 100644 --- a/hugr-py/src/hugr/hugr/__init__.py +++ b/hugr-py/src/hugr/hugr/__init__.py @@ -13,12 +13,8 @@ "Hugr", "NodeData", "Direction", - "Hugr", "InPort", "Wire", "OutPort", "Node", - "NodeData", - "OutPort", - "Wire", ] From 6ca653e189f42db40698344d0207ad03538bee21 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 11:54:13 +0000 Subject: [PATCH 17/34] minimal methods for ComposablePass --- hugr-py/src/hugr/passes/composable_pass.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 0ad945996b..c7b3844fdd 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -5,7 +5,6 @@ from typing_extensions import Self from hugr.hugr.base import Hugr -from hugr.hugr.node_port import Node class ComposablePass(Protocol): @@ -14,11 +13,3 @@ class ComposablePass(Protocol): def __call__(self, hugr: Hugr) -> None: ... def then(self, other: Self) -> Self: ... - - def with_entrypoint(self, entrypoint: Node) -> Self: ... - - @property - def is_global(self) -> bool: ... - - @property - def is_recursive(self) -> bool: ... From 9171dba76d10d2245493921ebcf9b4420ccbf58b Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 11:59:12 +0000 Subject: [PATCH 18/34] add ComposedPass dataclass --- hugr-py/src/hugr/passes/composable_pass.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index c7b3844fdd..43a9c5fe95 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -1,6 +1,7 @@ """A Protocol for a composable pass.""" from typing import Protocol +from dataclasses import dataclass from typing_extensions import Self @@ -13,3 +14,14 @@ class ComposablePass(Protocol): def __call__(self, hugr: Hugr) -> None: ... def then(self, other: Self) -> Self: ... + + +@dataclass +class ComposedPass(ComposablePass): + """A Sequence of composable passes.""" + passes: list[ComposablePass] + + def __call__(self, hugr: Hugr): + for comp_pass in self.passes: + self.comp_pass(hugr) + From c6fbfc0920eeb008947b0afd0db7d902f53a77ef Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 12:08:33 +0000 Subject: [PATCH 19/34] fix to comp_pass --- hugr-py/src/hugr/passes/composable_pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 43a9c5fe95..39746eb6f7 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -23,5 +23,5 @@ class ComposedPass(ComposablePass): def __call__(self, hugr: Hugr): for comp_pass in self.passes: - self.comp_pass(hugr) + comp_pass(hugr) From fcf00c0c44871a364c39c1f0dcdfda33406f9be2 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 12:21:33 +0000 Subject: [PATCH 20/34] docstrings --- hugr-py/src/hugr/passes/composable_pass.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 39746eb6f7..31d6ab50d3 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -11,17 +11,22 @@ class ComposablePass(Protocol): """A Protocol which represents a composable Hugr transformation.""" - def __call__(self, hugr: Hugr) -> None: ... + def __call__(self, hugr: Hugr) -> None: + """Call the pass to transform a HUGR.""" + ... - def then(self, other: Self) -> Self: ... + def then(self, other: Self) -> Self: + """Perform another composable pass after this pass.""" + ... @dataclass class ComposedPass(ComposablePass): - """A Sequence of composable passes.""" + """A sequence of composable passes.""" passes: list[ComposablePass] def __call__(self, hugr: Hugr): + """Call all of the passes in sequence.""" for comp_pass in self.passes: comp_pass(hugr) From 3ae525c198c7f84505aa368155ec41be5a6e258c Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 12:23:24 +0000 Subject: [PATCH 21/34] formatting stuff --- hugr-py/src/hugr/passes/composable_pass.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 31d6ab50d3..e53d9db9c1 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -16,17 +16,17 @@ def __call__(self, hugr: Hugr) -> None: ... def then(self, other: Self) -> Self: - """Perform another composable pass after this pass.""" - ... + """Perform another composable pass after this pass.""" + ... @dataclass class ComposedPass(ComposablePass): - """A sequence of composable passes.""" - passes: list[ComposablePass] - - def __call__(self, hugr: Hugr): - """Call all of the passes in sequence.""" - for comp_pass in self.passes: - comp_pass(hugr) - + """A sequence of composable passes.""" + + passes: list[ComposablePass] + + def __call__(self, hugr: Hugr): + """Call all of the passes in sequence.""" + for comp_pass in self.passes: + comp_pass(hugr) From af225a334e128e93fb9c99ffa634be3bbc4fb3b7 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 13:41:37 +0000 Subject: [PATCH 22/34] more ruff check --- hugr-py/src/hugr/passes/composable_pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index e53d9db9c1..65dc06875a 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -1,7 +1,7 @@ """A Protocol for a composable pass.""" -from typing import Protocol from dataclasses import dataclass +from typing import Protocol from typing_extensions import Self From 92964a8d9d3d6d0436e0fdff5efbe2520d5838b4 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:13:23 +0000 Subject: [PATCH 23/34] provide a default implementation of then() method --- hugr-py/src/hugr/passes/composable_pass.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 65dc06875a..b7ece2fe95 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -17,7 +17,15 @@ def __call__(self, hugr: Hugr) -> None: def then(self, other: Self) -> Self: """Perform another composable pass after this pass.""" - ... + pass_list = [] + if isinstance(self, ComposedPass) or isinstance(other, ComposedPass): + if isinstance(self, ComposedPass): + pass_list.append(self.passes) + elif isinstance(other, ComposedPass): + pass_list.append(other.passes) + else: + return ComposedPass([self, other]) + @dataclass From f139d7c67bb81d48baebe1cc1fe51103921c1f69 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:19:58 +0000 Subject: [PATCH 24/34] fix default impl --- hugr-py/src/hugr/passes/composable_pass.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index b7ece2fe95..c8d6bdd925 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -17,12 +17,12 @@ def __call__(self, hugr: Hugr) -> None: def then(self, other: Self) -> Self: """Perform another composable pass after this pass.""" - pass_list = [] + # Provide a default implementation for composing passes. if isinstance(self, ComposedPass) or isinstance(other, ComposedPass): - if isinstance(self, ComposedPass): - pass_list.append(self.passes) - elif isinstance(other, ComposedPass): - pass_list.append(other.passes) + if isinstance(self, ComposedPass) and not isinstance(other, ComposedPass): + return ComposedPass([self.passes, other]) + elif isinstance(other, ComposedPass) and not isinstance(self, ComposedPass): + return ComposedPass([self, other.passes]) else: return ComposedPass([self, other]) From df0ab1577bcfe84e16125e8f0c6719a7da0538e5 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:40:45 +0000 Subject: [PATCH 25/34] fixup then impl --- hugr-py/src/hugr/passes/composable_pass.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index c8d6bdd925..6fbefa72b0 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -15,16 +15,21 @@ def __call__(self, hugr: Hugr) -> None: """Call the pass to transform a HUGR.""" ... - def then(self, other: Self) -> Self: + def then(self, other: Self) -> ComposedPass: """Perform another composable pass after this pass.""" # Provide a default implementation for composing passes. - if isinstance(self, ComposedPass) or isinstance(other, ComposedPass): - if isinstance(self, ComposedPass) and not isinstance(other, ComposedPass): - return ComposedPass([self.passes, other]) - elif isinstance(other, ComposedPass) and not isinstance(self, ComposedPass): - return ComposedPass([self, other.passes]) + pass_list = [] + if isinstance(self, ComposedPass): + pass_list.extend(self.passes) else: - return ComposedPass([self, other]) + pass_list.append(self) + + if isinstance(other, ComposedPass): + pass_list.extend(other.passes) + else: + pass_list.append(other) + + return ComposedPass(pass_list) From ac63dd54a0c5986db731fc32a6e40243944c19c4 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:50:36 +0000 Subject: [PATCH 26/34] fixup mypy and ruff --- hugr-py/src/hugr/passes/composable_pass.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 6fbefa72b0..9d5b100d9c 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -1,4 +1,5 @@ """A Protocol for a composable pass.""" +from __future__ import annotations from dataclasses import dataclass from typing import Protocol @@ -15,7 +16,7 @@ def __call__(self, hugr: Hugr) -> None: """Call the pass to transform a HUGR.""" ... - def then(self, other: Self) -> ComposedPass: + def then(self, other: Self) -> ComposablePass: """Perform another composable pass after this pass.""" # Provide a default implementation for composing passes. pass_list = [] @@ -23,14 +24,13 @@ def then(self, other: Self) -> ComposedPass: pass_list.extend(self.passes) else: pass_list.append(self) - + if isinstance(other, ComposedPass): pass_list.extend(other.passes) else: pass_list.append(other) - - return ComposedPass(pass_list) + return ComposedPass([self, other]) @dataclass From 9a157b8d08b607f6ed922dc12c15a3c72306b76f Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:51:15 +0000 Subject: [PATCH 27/34] yet another fix --- hugr-py/src/hugr/passes/composable_pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 9d5b100d9c..3ef85e8ce0 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -30,7 +30,7 @@ def then(self, other: Self) -> ComposablePass: else: pass_list.append(other) - return ComposedPass([self, other]) + return ComposedPass(pass_list) @dataclass From 3db5bdd8773bf9afea2478d8787ef7c31148cd51 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:52:17 +0000 Subject: [PATCH 28/34] more ruff nonsense --- hugr-py/src/hugr/passes/composable_pass.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 3ef85e8ce0..9f79ce4f16 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -1,4 +1,5 @@ """A Protocol for a composable pass.""" + from __future__ import annotations from dataclasses import dataclass From 67d7d3858cc07964b494e6509e1aa3e2d6d504cc Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:53:08 +0000 Subject: [PATCH 29/34] rm self --- hugr-py/src/hugr/passes/composable_pass.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 9f79ce4f16..4cde6fcc18 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -5,8 +5,6 @@ from dataclasses import dataclass from typing import Protocol -from typing_extensions import Self - from hugr.hugr.base import Hugr @@ -17,7 +15,7 @@ def __call__(self, hugr: Hugr) -> None: """Call the pass to transform a HUGR.""" ... - def then(self, other: Self) -> ComposablePass: + def then(self, other: ComposablePass) -> ComposablePass: """Perform another composable pass after this pass.""" # Provide a default implementation for composing passes. pass_list = [] From 975ddbb03806c0198e3db9fc9b86e723d0656e18 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 15:56:22 +0000 Subject: [PATCH 30/34] fixes --- hugr-py/src/hugr/passes/composable_pass.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 4cde6fcc18..09981587a3 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -3,9 +3,10 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Protocol +from typing import TYPE_CHECKING, Protocol -from hugr.hugr.base import Hugr +if TYPE_CHECKING: + from hugr.hugr.base import Hugr class ComposablePass(Protocol): From 0165ae777c4d669c882cf1ee3bbd00d46af58061 Mon Sep 17 00:00:00 2001 From: Callum Macpherson <93673602+CalMacCQ@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:35:17 +0000 Subject: [PATCH 31/34] Update hugr-py/src/hugr/passes/composable_pass.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Agustín Borgna <121866228+aborgna-q@users.noreply.github.com> --- hugr-py/src/hugr/passes/composable_pass.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 09981587a3..485c67a064 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -31,7 +31,9 @@ def then(self, other: ComposablePass) -> ComposablePass: pass_list.append(other) return ComposedPass(pass_list) - + def name(self) -> str: + """Returns the name of the Pass""" + return self.__class__.__name__ @dataclass class ComposedPass(ComposablePass): From 2def5fc001e8eeb782f8c752cb5b263375ad4f32 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 16:36:43 +0000 Subject: [PATCH 32/34] fmt --- hugr-py/src/hugr/passes/composable_pass.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index 485c67a064..c81dd62197 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -16,6 +16,10 @@ def __call__(self, hugr: Hugr) -> None: """Call the pass to transform a HUGR.""" ... + def name(self) -> str: + """Returns the name of the pass.""" + return self.__class__.__name__ + def then(self, other: ComposablePass) -> ComposablePass: """Perform another composable pass after this pass.""" # Provide a default implementation for composing passes. @@ -31,9 +35,7 @@ def then(self, other: ComposablePass) -> ComposablePass: pass_list.append(other) return ComposedPass(pass_list) - def name(self) -> str: - """Returns the name of the Pass""" - return self.__class__.__name__ + @dataclass class ComposedPass(ComposablePass): From 9673dc29b35ac3a81fdf81c6214e6e310e247926 Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 17:01:15 +0000 Subject: [PATCH 33/34] make name a property --- hugr-py/src/hugr/passes/composable_pass.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hugr-py/src/hugr/passes/composable_pass.py b/hugr-py/src/hugr/passes/composable_pass.py index c81dd62197..90f41fb0e5 100644 --- a/hugr-py/src/hugr/passes/composable_pass.py +++ b/hugr-py/src/hugr/passes/composable_pass.py @@ -3,12 +3,13 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING, Protocol +from typing import TYPE_CHECKING, Protocol, runtime_checkable if TYPE_CHECKING: from hugr.hugr.base import Hugr +@runtime_checkable class ComposablePass(Protocol): """A Protocol which represents a composable Hugr transformation.""" @@ -16,6 +17,7 @@ def __call__(self, hugr: Hugr) -> None: """Call the pass to transform a HUGR.""" ... + @property def name(self) -> str: """Returns the name of the pass.""" return self.__class__.__name__ From 01b71269baf9a60c61dd28f7a367f02b29a767cf Mon Sep 17 00:00:00 2001 From: Callum Macpherson Date: Wed, 12 Nov 2025 17:01:32 +0000 Subject: [PATCH 34/34] add a dummy test --- hugr-py/tests/test_passes.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 hugr-py/tests/test_passes.py diff --git a/hugr-py/tests/test_passes.py b/hugr-py/tests/test_passes.py new file mode 100644 index 0000000000..542ef1f8b5 --- /dev/null +++ b/hugr-py/tests/test_passes.py @@ -0,0 +1,26 @@ +from hugr.hugr.base import Hugr +from hugr.passes.composable_pass import ComposablePass, ComposedPass + + +def test_composable_pass() -> None: + class MyDummyPass(ComposablePass): + def __call__(self, hugr: Hugr) -> None: + return self(hugr) + + def then(self, other: ComposablePass) -> ComposablePass: + return ComposedPass([self, other]) + + @property + def name(self) -> str: + return "Dummy" + + dummy = MyDummyPass() + + composed = dummy.then(dummy) + + my_composed_pass = ComposedPass([dummy, dummy]) + + assert my_composed_pass.passes == [dummy, dummy] + assert isinstance(my_composed_pass, ComposablePass) + assert isinstance(composed, ComposablePass) + assert dummy.name == "Dummy"