qcs 0.27.0

High level interface for running Quil on a QPU
Documentation
[env]
RUST_BACKTRACE = 0
CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = "--features libquil,_insecure-issuer-validation,stubs"  # Disable --all-features to avoid manual tests in CI for now

[tasks.pre-test]
command = "docker"
args = ["compose", "up", "-d"]

[tasks.post-test]
command = "docker"
args = ["compose", "down"]

[tasks.serve-docs]
command = "cargo"
args = ["doc", "--open"]

[tasks.manual]
env = {CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = "--all-features"}
run_task = [{name = "test-flow"}]

[tasks.lint]
dependencies = ["clippy-flow"]

[tasks.examples]
dependencies = ["examples-libquil", "examples-experimental"]

[tasks.examples-libquil]
command = "cargo"
args = ["build", "--examples", "--features", "libquil"]

[tasks.examples-experimental]
command = "cargo"
args = ["build", "--examples", "--features", "experimental"]

[tasks.deny]
install_crate = "cargo-deny"
command = "cargo"
args = ["deny", "--exclude-dev", "--all-features", "check"]

[tasks.check]
command = "cargo"
args = ["hack", "check", "--feature-powerset", "--depth", "2", "--all-targets"]

[tasks.ci-flow]
dependencies = ["deny", "lint", "check", "test-flow"]

# ----

[tasks.generate-stubs]
description = "Generate Python stub files."
dependencies = ["generate-stubs-impl", "format-stubs"]

# The task to actually run the stub generator
[tasks.generate-stubs-impl]
private = true
command = "uv"
args = ["run", "cargo", "run", "-p", "qcs", "--features", "stubs", "--bin", "stub_gen"]

[tasks.format-stubs]
description = "Format Python stubs."
command = "uv"
args = ["run", "--group", "dev", "ruff", "format", "python/qcs_sdk"]

[tasks.check-generated-python-files]
# The generated `__init__.py` files are what expose the compiled `qcs_sdk._qcs_sdk` modules
# under their public `qcs_sdk` names, and release wheels are built straight from the committed
# tree (see `.github/workflows/release-python.yml`, which does not run `cargo make`). So if
# they go stale, a release can silently omit a class — or a whole submodule — with nothing else
# to catch it.
description = "Check that the committed stubs and `__init__.py` files are up to date."
dependencies = ["generate-stubs"]
cwd = "python"
script = '''
if [ -n "$(git status --porcelain .)" ]; then
    echo "error: the generated Python files are out of date." >&2
    echo "Run 'cargo make --cwd crates/lib generate-stubs' and commit the result:" >&2
    git status --porcelain . >&2
    git --no-pager diff . >&2
    exit 1
fi
echo "Generated Python files are up to date."
'''

[tasks.package-python]
description = "Build a release version of the Python package."
dependencies = ["generate-stubs"]
command = "uv"
args = ["run", "--group", "dev", "maturin", "build", "--release"]

[tasks.install-python-package]
# `generate-stubs` also writes the package's `__init__.py` files, which are what expose the
# compiled `qcs_sdk._qcs_sdk` modules under their public `qcs_sdk` names — so it is a build
# input now, not just a convenience for type checkers.
description = "Build the Python package and install to the active virtual environment."
dependencies = ["generate-stubs"]
command = "uv"
args = ["run", "--group", "dev", "maturin", "develop"]

[tasks.pytest]
description = "Run Python tests."
dependencies = ["install-python-package"]
command = "uv"
args = ["run", "--group", "dev", "pytest"]

[tasks.pytest-flow]
dependencies = [
    "pre-test",
    "install-python-package",
    "pytest",
    "post-test",
]

[tasks.stubtest]
description = "Check Python stubfiles."
dependencies = ["install-python-package"]
command = "uv"
cwd = "python"
args = [
    "run",
    "--group",
    "dev",
    "stubtest",
    "--allowlist",
    "stubtest-allowlist",
    "--allowlist",
    "./qcs_sdk/_tracing_subscriber/.stubtest-allowlist",
    "--ignore-disjoint-bases",
    "qcs_sdk",
]

[tasks.stubtest-flow]
dependencies = ["stubtest"]

[tasks.lint-python-package]
description = "Find errors in Python-related Rust code."
dependencies = ["install-python-package"]
command = "uv"
args = ["run", "--group", "dev", "python", "./scripts/lint-bindings.py", "--base", "src", "--show-mistakes"]

[tasks.show-python-package-layout]
description = "Print the Python package layout as defined within Rust code."
dependencies = ["install-python-package"]
command = "uv"
args = ["run", "--group", "dev", "python", "./scripts/lint-bindings.py", "--base", "src", "--show-package"]

[tasks.test-python-package]
description = "Run all Python-related tests."
dependencies = [
    "lint-python-package",
    "check-generated-python-files",
    "check-python-api",
    "stubtest-flow",
    "pytest-flow",
]

[tasks.test-all]
description = "Run all tests."
dependencies = ["test", "test-python-package"]

[tasks.default]
alias = "test-all"

[tasks.check-python-api]
description = "Check if Python API has breaking changes."
dependencies = ["install-python-package"]
script = { file = "./scripts/check-py-api.sh" }

[tasks.document-python-package]
description = "Generate Python package documentation."
dependencies = ["install-python-package"]
command = "uv"
args = [
    "run",
    "--group",
    "dev", 
    "pdoc",
    "-o", "build/docs",
    "qcs_sdk",
    "!qcs_sdk._qcs_sdk",
    "--logo", "https://qcs.rigetti.com/static/img/rigetti-logo.svg",
]

# ----

[tasks.format-tracing-subscriber]
command = "uv"
args = ["run", "--group", "dev", "ruff", "format", "python/qcs_sdk/_tracing_subscriber"]

[tasks.format]
# Only hand-written Python. Everything under `python/qcs_sdk` is generated — reformatting it
# makes `check-generated-python-files` fail until the next `generate-stubs` run.
# (`tests` is the Rust integration-test directory and contains no Python.)
command = "uv"
args = ["run", "--group", "dev", "ruff", "format", "tests_py", "scripts"]

[tasks.test-session]
dependencies = ["install-python-package"]
command = "uv"
args = ["run", "--group", "dev", "pytest", "tests_py", "--with-qcs-session"]

[tasks.test-execution]
dependencies = ["install-python-package"]
command = "uv"
args = ["run", "--group", "dev", "pytest", "tests_py", "--with-qcs-session", "--with-qcs-execution"]

[tasks.dev-flow]
dependencies = ["dev-test-flow", "pytest-flow", "stubtest-flow"]