diff --git a/devenv.nix b/devenv.nix index e0dea5c..10294c4 100644 --- a/devenv.nix +++ b/devenv.nix @@ -9,18 +9,14 @@ in pkgs-unstable.uv pkgs.commitizen pkgs.git + pkgs.just ]; dotenv.enable = true; # https://devenv.sh/scripts/ scripts.qfmt.exec = '' - echo -e "Running formatting, linting and typechecking ๐Ÿงน ๐Ÿ”ง \n" - - uv run ruff check --select I --fix - uv run ruff check - uv run ruff format - uv run mypy qnexus/ tests/ integration/ + just qfmt ''; scripts.qtest.exec = '' echo -e "Running unit tests ๐Ÿ“๐Ÿ”\n" diff --git a/integration/conftest.py b/integration/conftest.py index 1c09591..6fdf70f 100644 --- a/integration/conftest.py +++ b/integration/conftest.py @@ -463,7 +463,7 @@ def test_ref_serialisation( @pytest.fixture(name="qa_hugr_package") def qa_hugr_package_fixture() -> Package: - hugr_path = Path("tests/data/example.hugr").resolve() + hugr_path = Path("tests/data/example_bell.hugr").resolve() return Package.from_bytes(hugr_path.read_bytes()) diff --git a/integration/test_qsys_jobs.py b/integration/test_qsys_jobs.py index 4ca941d..7777800 100644 --- a/integration/test_qsys_jobs.py +++ b/integration/test_qsys_jobs.py @@ -1,11 +1,9 @@ """Tests related to running jobs against QSys devices.""" -from typing import Any, Callable, ContextManager, cast +from typing import Callable, ContextManager, cast import pytest -from guppylang import guppy -from guppylang.std.builtins import result -from guppylang.std.quantum import cx, h, measure, qubit, x, z +from hugr.package import Package from hugr.qsystem.result import QsysResult from pytket.backends.backendinfo import BackendInfo from quantinuum_schemas.models.backend_config import ( @@ -24,36 +22,6 @@ ) -def prepare_teleportation() -> Any: - """Prepares the teleportation circuit.""" - - @guppy - def bell() -> tuple[qubit, qubit]: - """Constructs a bell state.""" - q1, q2 = qubit(), qubit() - h(q1) - cx(q1, q2) - return q1, q2 - - @guppy - def main() -> None: - src = qubit() - x(src) - alice, bob = bell() - - cx(src, alice) - h(src) - if measure(alice): - x(bob) - if measure(src): - z(bob) - - result("teleported", measure(bob)) - - main.check() - return main.compile() - - @pytest.mark.parametrize( "backend_config", [ @@ -70,6 +38,7 @@ def test_guppy_execution( test_case_name: str, create_project: Callable[[str], ContextManager[ProjectRef]], backend_config: BackendConfig, + qa_hugr_package: Package, ) -> None: """Test the execution of a guppy program on a next-generation QSys device.""" @@ -78,7 +47,7 @@ def test_guppy_execution( n_shots = 10 hugr_ref = qnx.hugr.upload( - hugr_package=prepare_teleportation(), + hugr_package=qa_hugr_package, name=f"hugr for {test_case_name}", project=project_ref, ) @@ -127,12 +96,13 @@ def test_guppy_execution( def test_hugr_costing( test_case_name: str, create_project: Callable[[str], ContextManager[ProjectRef]], + qa_hugr_package: Package, ) -> None: """Test the costing of a Hugr program on a cost checking device.""" with create_project(f"project for {test_case_name}") as project_ref: hugr_ref = qnx.hugr.upload( - hugr_package=prepare_teleportation(), + hugr_package=qa_hugr_package, name=f"hugr for {test_case_name}", project=project_ref, ) diff --git a/justfile b/justfile new file mode 100644 index 0000000..94f6c92 --- /dev/null +++ b/justfile @@ -0,0 +1,17 @@ +# List the available commands +help: + @just --list --justfile {{justfile()}} + +# Run basic formatting, linting and typechecking +qfmt: + echo -e "Running formatting, linting and typechecking ๐Ÿงน ๐Ÿ”ง \n" + + uv run ruff check --select I --fix + uv run ruff check + uv run ruff format + uv run mypy qnexus/ tests/ integration/ + +# Re-compile test hugr files. +recompile-test-files: + @echo "---- Recompiling example guppy programs ----" + just tests/data/recompile \ No newline at end of file diff --git a/pytest.ini b/pytest.ini index 6b6d4eb..7f92fc3 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,5 @@ [pytest] addopts = --strict-markers -n 2 --reruns 3 --cov=qnexus --cov-report= --cov-append --doctest-modules +norecursedirs = tests/data markers = create: marks tests as those that have side effects involving resource creation (deselect with '-m "not create"') diff --git a/tests/data/README.md b/tests/data/README.md new file mode 100644 index 0000000..75b1a00 --- /dev/null +++ b/tests/data/README.md @@ -0,0 +1,8 @@ +# Test programs + +This directory contains simple quantum programs used for testing. + +The compiled HUGR is stored (alongside the guppy python program) with a `.hugr` extension. + +Run `just recompile` in this directory (or `just recompile-test-files` on +the root) to recompile the `.hugr` files. diff --git a/tests/data/example.hugr b/tests/data/example.hugr deleted file mode 100644 index a1a6f80..0000000 Binary files a/tests/data/example.hugr and /dev/null differ diff --git a/tests/data/example_bell.gpy.py b/tests/data/example_bell.gpy.py new file mode 100644 index 0000000..e0ef2d3 --- /dev/null +++ b/tests/data/example_bell.gpy.py @@ -0,0 +1,39 @@ +"""Simple guppylang program from https://docs.quantinuum.com/guppy""" + +from pathlib import Path +from sys import argv + +from guppylang import guppy +from guppylang.std.builtins import result +from guppylang.std.quantum import cx, h, measure, qubit, x, z + + +@guppy +def bell() -> tuple[qubit, qubit]: + """Constructs a bell state.""" + q1, q2 = qubit(), qubit() + h(q1) + cx(q1, q2) + return q1, q2 + + +@guppy +def main() -> None: + src = qubit() + x(src) + alice, bob = bell() + + cx(src, alice) + h(src) + if measure(alice): + x(bob) + if measure(src): + z(bob) + + result("teleported", measure(bob)) + + +main.check() +program = main.compile_function() +# remove the .gpy suffix and add .hugr +Path(argv[0]).with_suffix("").with_suffix(".hugr").write_bytes(program.to_bytes()) diff --git a/tests/data/example_bell.hugr b/tests/data/example_bell.hugr new file mode 100644 index 0000000..89b6bb7 Binary files /dev/null and b/tests/data/example_bell.hugr differ diff --git a/tests/data/justfile b/tests/data/justfile new file mode 100644 index 0000000..5943812 --- /dev/null +++ b/tests/data/justfile @@ -0,0 +1,14 @@ +# List the available commands +help: + @just --list --justfile {{justfile()}} + +# Re-generate all test hugr files. +recompile: recompile-test-files + +# Re-generate all hugr files. +recompile-test-files: + #!/usr/bin/env sh + for example in $(find . -type f -name "*.gpy.py"); do + echo "Re-generating $example" + uv run --no-project "$example" + done \ No newline at end of file