diff --git a/hugr-py/src/hugr/hugr/render.py b/hugr-py/src/hugr/hugr/render.py index 84258b67a..d866af777 100644 --- a/hugr-py/src/hugr/hugr/render.py +++ b/hugr-py/src/hugr/hugr/render.py @@ -9,7 +9,7 @@ from typing_extensions import assert_never from hugr.hugr import Hugr -from hugr.ops import AsExtOp +from hugr.ops import AsExtOp, Case from hugr.tys import CFKind, ConstKind, FunctionKind, Kind, OrderKind, ValueKind from .node_port import InPort, Node, OutPort @@ -243,8 +243,22 @@ def _in_order_name(self, n: Node) -> str: def _out_order_name(self, n: Node) -> str: return f"{n.idx}:{self._OUTPUT_PREFIX}None" - def _viz_node(self, node: Node, hugr: Hugr, graph: Digraph) -> None: - """Render a (possibly nested) node to a graphviz graph.""" + def _viz_node( + self, + node: Node, + hugr: Hugr, + graph: Digraph, + *, + sibling_order: int | None = None, + ) -> None: + """Render a (possibly nested) node to a graphviz graph. + + Args: + node: The node to render. + hugr: The HUGR to render. + graph: The graphviz graph to render the node to. + sibling_order: The order of the node in the region's sibling list. + """ meta = hugr[node].metadata if len(meta) > 0 and self.config.display_metadata: if self.config.max_metadata_length is not None: @@ -278,6 +292,9 @@ def _viz_node(self, node: Node, hugr: Hugr, graph: Digraph) -> None: op = hugr[node].op if isinstance(op, AsExtOp) and not self.config.qualify_op_name: op_name = op.op_def().name + elif isinstance(op, Case) and sibling_order is not None: + # Indicate the case number + op_name = f"{op.name()}[{sibling_order}]" else: op_name = op.name() @@ -311,8 +328,8 @@ def _viz_node(self, node: Node, hugr: Hugr, graph: Digraph) -> None: if hugr.children(node): with graph.subgraph(name=f"cluster{node.idx}") as sub: - for child in hugr.children(node): - self._viz_node(child, hugr, sub) + for sibling_order, child in enumerate(hugr.children(node)): + self._viz_node(child, hugr, sub, sibling_order=sibling_order) html_label = self._format_html_label(**label_config) sub.node(f"{node.idx}", shape="plain", label=f"<{html_label}>") sub.attr( diff --git a/hugr-py/src/hugr/ops.py b/hugr-py/src/hugr/ops.py index e1accf974..71cfc3a45 100644 --- a/hugr-py/src/hugr/ops.py +++ b/hugr-py/src/hugr/ops.py @@ -816,8 +816,18 @@ def __repr__(self) -> str: def __str__(self) -> str: if len(self.sum_ty.variant_rows) == 2: left, right = self.sum_ty.variant_rows - if len(left) == 0 and self.tag == 1: - return "Some" + if not left and not right: + # Boolean + if self.tag == 1: + return "True" + else: + return "False" + elif not left: + # Option + if self.tag == 1: + return "Some" + else: + return "None" elif self.tag == 0: return "Left" else: diff --git a/hugr-py/tests/__snapshots__/test_hugr_build.ambr b/hugr-py/tests/__snapshots__/test_hugr_build.ambr index 58f017583..9a7d44c7f 100644 --- a/hugr-py/tests/__snapshots__/test_hugr_build.ambr +++ b/hugr-py/tests/__snapshots__/test_hugr_build.ambr @@ -2593,7 +2593,7 @@ + COLOR="black">Case[0]
Case
@@ -2661,7 +2661,7 @@ + COLOR="black">Case[1]
Case
diff --git a/hugr-py/tests/test_ops.py b/hugr-py/tests/test_ops.py index fd6b8870d..de965a5a8 100644 --- a/hugr-py/tests/test_ops.py +++ b/hugr-py/tests/test_ops.py @@ -43,7 +43,10 @@ (DivMod, "arithmetic.int.idivmod_u<5>"), (MakeTuple(), "MakeTuple"), (UnpackTuple(), "UnpackTuple"), - (Tag(0, Bool), "Left"), + (Tag(0, Bool), "False"), + (Tag(1, Bool), "True"), + (Tag(0, tys.Option(Bool)), "None"), + (Tag(1, tys.Option(Bool)), "Some"), (Tag(0, tys.Sum([[Bool, Bool, Bool]])), "Tag(0)"), (CFG([]), "CFG"), (DFG([]), "DFG"), diff --git a/pyproject.toml b/pyproject.toml index 6d082eb6f..9b2ae7df1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,13 +6,14 @@ members = ["hugr-py"] dev-dependencies = [ "pre-commit >=3.6.2,<4", - "pytest >=8.1.1,<9", - "pytest-cov >=5.0.0,<6", + "pytest ~=9.0", + "pytest-cov ~=7.0", + "pytest-xdist ~= 3.8", "maturin >=1.7.0,<2", "mypy >=1.9.0,<2", "ruff >=0.6.2,<0.7", "toml >=0.10.0,<0.11", - "syrupy >=4.7.1,<5", + "syrupy ~=5.1", "types-zstd >= 1.5.6.6", "pytket >= 1.34.0", ] @@ -22,8 +23,6 @@ addopts = "--doctest-modules --ignore=test_files" filterwarnings = "ignore::DeprecationWarning:lark.*" - - [tool.mypy] # TODO: Fix lints and enable this #strict = true diff --git a/uv.lock b/uv.lock index 88323a0e3..5878a571e 100644 --- a/uv.lock +++ b/uv.lock @@ -16,11 +16,12 @@ dev = [ { name = "maturin", specifier = ">=1.7.0,<2" }, { name = "mypy", specifier = ">=1.9.0,<2" }, { name = "pre-commit", specifier = ">=3.6.2,<4" }, - { name = "pytest", specifier = ">=8.1.1,<9" }, - { name = "pytest-cov", specifier = ">=5.0.0,<6" }, + { name = "pytest", specifier = "~=9.0" }, + { name = "pytest-cov", specifier = "~=7.0" }, + { name = "pytest-xdist", specifier = "~=3.8" }, { name = "pytket", specifier = ">=1.34.0" }, { name = "ruff", specifier = ">=0.6.2,<0.7" }, - { name = "syrupy", specifier = ">=4.7.1,<5" }, + { name = "syrupy", specifier = "~=5.1" }, { name = "toml", specifier = ">=0.10.0,<0.11" }, { name = "types-zstd", specifier = ">=1.5.6.6" }, ] @@ -327,6 +328,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, ] +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + [[package]] name = "filelock" version = "3.20.3" @@ -1112,7 +1122,7 @@ wheels = [ [[package]] name = "pytest" -version = "8.4.2" +version = "9.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1123,22 +1133,36 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] [[package]] name = "pytest-cov" -version = "5.0.0" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042, upload-time = "2024-03-24T20:16:34.856Z" } +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990, upload-time = "2024-03-24T20:16:32.444Z" }, + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, ] [[package]] @@ -1640,14 +1664,14 @@ wheels = [ [[package]] name = "syrupy" -version = "4.9.1" +version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8c/f8/022d8704a3314f3e96dbd6bbd16ebe119ce30e35f41aabfa92345652fceb/syrupy-4.9.1.tar.gz", hash = "sha256:b7d0fcadad80a7d2f6c4c71917918e8ebe2483e8c703dfc8d49cdbb01081f9a4", size = 52492, upload-time = "2025-03-24T01:36:37.225Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/b0/24bca682d6a6337854be37f242d116cceeda9942571d5804c44bc1bdd427/syrupy-5.1.0.tar.gz", hash = "sha256:df543c7aa50d3cf1246e83d58fe490afe5f7dab7b41e74ecc0d8d23ae19bd4b8", size = 50495, upload-time = "2026-01-25T14:53:06.2Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/9d/aef9ec5fd5a4ee2f6a96032c4eda5888c5c7cec65cef6b28c4fc37671d88/syrupy-4.9.1-py3-none-any.whl", hash = "sha256:b94cc12ed0e5e75b448255430af642516842a2374a46936dd2650cfb6dd20eda", size = 52214, upload-time = "2025-03-24T01:36:35.278Z" }, + { url = "https://files.pythonhosted.org/packages/de/70/cf880c3b95a6034ef673e74b369941b42315c01f1554a5637a4f8b911009/syrupy-5.1.0-py3-none-any.whl", hash = "sha256:95162d2b05e61ed3e13f117b88dfab7c58bd6f90e66ebbf918e8a77114ad51c5", size = 51658, upload-time = "2026-01-25T14:53:05.105Z" }, ] [[package]]