Skip to content

Commit 6bf86be

Browse files
cqc-melftrvto
andauthored
improve error message (#135)
Improve error messages when QIR generation fails Drive-by: don't run snapshot checks on cibuildwheel (they tend to fail for unimportant reasons) Drive-by2: track pre-commit config --------- Co-authored-by: Travis Thompson <[email protected]> Co-authored-by: Travis Thompson <[email protected]>
1 parent c9000a8 commit 6bf86be

File tree

10 files changed

+1411
-1280
lines changed

10 files changed

+1411
-1280
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ devenv.local.nix
55
# direnv
66
.direnv
77

8-
# pre-commit
9-
.pre-commit-config.yaml
108
/.envrc
119

1210

.pre-commit-config.yaml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v4.5.0 # Use the ref you want to point at
4+
hooks:
5+
- id: check-added-large-files
6+
- id: check-case-conflict
7+
- id: check-executables-have-shebangs
8+
- id: check-merge-conflict
9+
- id: check-toml
10+
- id: check-vcs-permalinks
11+
- id: check-yaml
12+
- id: detect-private-key
13+
- id: end-of-file-fixer
14+
exclude: |
15+
(?x)^(
16+
specification/schema/.*|
17+
.*\.snap|
18+
.*\.snap\.new|
19+
.*\.ambr|
20+
.release-please-manifest.json|
21+
.*/snapshots/.*
22+
)$
23+
- id: trailing-whitespace
24+
exclude: |
25+
(?x)^(
26+
specification/schema/.*|
27+
.*\.snap|
28+
.*\.ambr|
29+
.*\.snap\.new|
30+
.*/snapshots/.*
31+
)$
32+
- id: fix-byte-order-marker
33+
- id: mixed-line-ending
34+
# Python-specific
35+
- id: check-ast
36+
- id: check-docstring-first
37+
- id: debug-statements
38+
39+
- repo: local
40+
hooks:
41+
- id: ruff-format
42+
name: ruff format
43+
description: Format python code with `ruff`.
44+
entry: uv run ruff format
45+
language: system
46+
files: \.py$
47+
pass_filenames: false
48+
- id: ruff-check
49+
name: ruff
50+
description: Check python code with `ruff`.
51+
entry: uv run ruff check --fix --exit-non-zero-on-fix
52+
language: system
53+
files: \.py$
54+
pass_filenames: false
55+
- id: mypy-check
56+
name: mypy
57+
description: Check python code with `mypy`.
58+
entry: uv run mypy .
59+
language: system
60+
files: \.py$
61+
pass_filenames: false
62+
- id: cargo-fmt
63+
name: cargo format
64+
description: Format rust code with `cargo fmt`.
65+
entry: cargo fmt --all -- --check
66+
language: system
67+
files: \.rs$
68+
pass_filenames: false
69+
- id: cargo-check
70+
name: cargo check
71+
description: Check rust code with `cargo check`.
72+
entry: cargo check --all --all-features --workspace
73+
language: system
74+
files: \.rs$
75+
pass_filenames: false
76+
- id: cargo-test
77+
name: cargo test
78+
description:
79+
Run tests with `cargo test`.
80+
# guppy tests require python/guppylang so use uv to run cargo test
81+
entry: uv run cargo test
82+
language: system
83+
files: \.rs$
84+
pass_filenames: false
85+
- id: cargo-clippy
86+
name: cargo clippy
87+
description: Run clippy lints with `cargo clippy`.
88+
entry: cargo clippy --all-targets --all-features --workspace -- -D warnings
89+
language: system
90+
files: \.rs$
91+
pass_filenames: false
92+
- id: cargo-doc
93+
name: cargo doc
94+
description: Generate documentation with `cargo doc`.
95+
entry: sh -c "RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features --workspace"
96+
language: system
97+
files: \.rs$
98+
pass_filenames: false

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "hugr-qir"
3-
version = "0.0.15"
3+
version = "0.0.16"
44
edition = "2024"
55
rust-version = "1.85"
66

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "hugr-qir"
3-
version = "0.0.15"
3+
version = "0.0.16"
44
description = "Quantinuum's tool for converting HUGR to QIR"
55
readme = "README.md"
66
requires-python = ">=3.10"
@@ -52,7 +52,7 @@ skip = "*-win32 *-manylinux_i686 *-musllinux*"
5252
manylinux-x86_64-image = "manylinux_2_34"
5353
test-groups = ["dev"]
5454
test-sources = ["python/tests", "guppy_examples"]
55-
test-command = "pytest python/tests -k test_guppy_files"
55+
test-command = "pytest python/tests"
5656

5757
[tool.cibuildwheel.linux.environment]
5858
PATH = '$HOME/.cargo/bin:/tmp/llvm/bin:$PATH'

python/hugr_qir/cli.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,28 @@ def hugr_qir_impl( # noqa: PLR0913
121121
tmp_outfile_name = f"{tmp_dir}/tmp.ll" # noqa: S108
122122
tmp_outfile_path = Path(tmp_outfile_name)
123123
tmp_options = [*options, "-o", tmp_outfile_name]
124-
cli(str(hugr_file), *tmp_options)
125-
with Path.open(tmp_outfile_path) as output:
126-
qir = output.read()
124+
failedqirmsg = "QIR generation failed. This may be the result of a bug \
125+
but can also happen when trying to convert a feature in HUGR/Guppylang \
126+
which is not supported in QIR."
127+
try:
128+
cli(str(hugr_file), *tmp_options)
129+
except RuntimeError as e:
130+
msg = f"{failedqirmsg} Error details: {e}"
131+
raise ValueError(msg) from e
132+
try:
133+
with Path.open(tmp_outfile_path) as output:
134+
qir = output.read()
135+
except FileNotFoundError as e:
136+
msg = f"{failedqirmsg} Error details: {e}"
137+
raise ValueError(msg) from e
127138
if validate_qir:
128139
try:
129140
qircheck(qir)
130141
except ValidationError as e:
131-
msg = f"Found a problem in the generated QIR: {e}"
142+
msg = f"{failedqirmsg} The failure occurred in the validity check of the \
143+
generated QIR. This check can be disabled by setting `--no-validate-qir`\
144+
on the cli or passing `validate_qir=False` for library calls. Error \
145+
details: {e}"
132146
raise ValueError(msg) from e
133147

134148
llvm_write_mode = get_write_mode(output_format)

python/tests/conftest.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
1+
import os
12
import subprocess
23
import sys
34
import tempfile
45
from pathlib import Path
56
from typing import IO
67

8+
import pytest
79
from click.testing import CliRunner
810
from hugr_qir.cli import hugr_qir
911

1012
GUPPY_EXAMPLES_DIR_GENERAL = Path(__file__).parent / "../../guppy_examples/general"
1113
GUPPY_EXAMPLES_DIR_QHO = (
1214
Path(__file__).parent / "../../guppy_examples/quantinuum-hardware-only"
1315
)
16+
# Within the cibuildwheels environments, ssa variable names tend to be slightly
17+
# different, so verbatim snapshot tests do not pass. So we just test
18+
# that generation works for the wheel builds
19+
skip_snapshot_checks = os.getenv("CIBUILDWHEEL") == "1"
20+
21+
22+
def pytest_configure(config: pytest.Config) -> None:
23+
if skip_snapshot_checks:
24+
config.issue_config_time_warning(
25+
UserWarning(
26+
"Detected tests running on cibuildwheel,"
27+
" so skipping all snapshot checks"
28+
),
29+
stacklevel=2,
30+
)
1431

1532

1633
def guppy_to_hugr_file(guppy_file: Path, outfd: IO) -> None:

python/tests/test_guppy_examples.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
GUPPY_EXAMPLES_DIR_GENERAL,
1010
cli_on_guppy,
1111
guppy_files,
12+
skip_snapshot_checks,
1213
)
1314

1415
SNAPSHOT_DIR = Path(__file__).parent / "snapshots"
@@ -49,7 +50,8 @@ def test_guppy_file_snapshots(
4950
)
5051
with Path.open(out_file) as f:
5152
qir = f.read()
52-
snapshot.assert_match(qir, str(Path(guppy_file.stem).with_suffix(".ll")))
53+
if not skip_snapshot_checks:
54+
snapshot.assert_match(qir, str(Path(guppy_file.stem).with_suffix(".ll")))
5355

5456

5557
@pytest.mark.parametrize(
@@ -76,7 +78,7 @@ def test_guppy_files_options(
7678
with Path.open(out_file, mode=file_read_mode) as f:
7779
qir = f.read()
7880
# don't test snapshots for 'native' since output is machine-dependent
79-
if target != "native":
81+
if target != "native" and not skip_snapshot_checks:
8082
snapshot_filename = guppy_file.stem + "_" + target + "_" + opt_level
8183
snapshot.assert_match(
8284
qir, str(Path(snapshot_filename).with_suffix(file_suffix))

python/tests/test_hugr_to_qir.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
GUPPY_EXAMPLES_DIR_GENERAL,
1818
guppy_files,
1919
guppy_to_hugr_binary,
20+
skip_snapshot_checks,
2021
)
2122

2223
SNAPSHOT_DIR = Path(__file__).parent / "snapshots"
@@ -61,7 +62,8 @@ def test_guppy_file_snapshots(guppy_file: Path, snapshot: Snapshot) -> None:
6162
snapshot.snapshot_dir = SNAPSHOT_DIR
6263
hugr = guppy_to_hugr_binary(guppy_file)
6364
qir = hugr_to_qir(hugr, validate_qir=False, output_format=OutputFormat.LLVM_IR)
64-
snapshot.assert_match(qir, str(Path(guppy_file.stem).with_suffix(".ll")))
65+
if not skip_snapshot_checks:
66+
snapshot.assert_match(qir, str(Path(guppy_file.stem).with_suffix(".ll")))
6567

6668

6769
@pytest.mark.parametrize(
@@ -110,7 +112,7 @@ def test_guppy_files_options(
110112
output_format=OutputFormat(out_format),
111113
)
112114
# don't test snapshots for 'native' since output is machine-dependent
113-
if target != "native":
115+
if target != "native" and not skip_snapshot_checks:
114116
file_suffix = expected_file_extension(out_format)
115117
snapshot_filename = guppy_file.stem + "_" + target + "_" + opt_level
116118
snapshot.assert_match(

0 commit comments

Comments
 (0)