Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 63 additions & 60 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,30 @@
from __future__ import annotations

import argparse
import contextlib
import os
import shutil
import tempfile
from typing import TYPE_CHECKING

import nox

if TYPE_CHECKING:
from collections.abc import Generator, Sequence
from collections.abc import Sequence


nox.needs_version = ">=2025.10.16"
nox.needs_version = ">=2026.08.10"
nox.options.default_venv_backend = "uv"

PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12", "3.13", "3.14"]
nox.options.parallel = "auto"

if os.environ.get("CI", None):
nox.options.error_on_missing_interpreters = True

PYPROJECT = nox.project.load_toml("pyproject.toml")
PYTHON_VERSIONS = nox.project.python_versions(PYPROJECT)


@contextlib.contextmanager
def preserve_lockfile() -> Generator[None]:
"""Preserve the lockfile by moving it to a temporary directory."""
with tempfile.TemporaryDirectory() as temp_dir_name:
shutil.move("uv.lock", f"{temp_dir_name}/uv.lock")
try:
yield
finally:
shutil.move(f"{temp_dir_name}/uv.lock", "uv.lock")
def _get_session_env(session: nox.Session) -> dict[str, str]:
"""Return the environment that a session installs the project in."""
return {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}


@nox.session(reuse_venv=True, default=True)
Expand All @@ -57,24 +51,44 @@ def lint(session: nox.Session) -> None:
session.run("prek", "run", "--all-files", *session.posargs, external=True)


def _run_tests(
@nox.session(python=PYTHON_VERSIONS, reuse_venv=True, default=True, allow_parallel=True)
def tests(session: nox.Session) -> None:
"""Run the test suite."""
session.run(
"uv",
"run",
"--no-dev",
"--group",
"test",
"pytest",
*session.posargs,
"--cov-config=pyproject.toml",
env=_get_session_env(session),
)


def _run_tests_without_lockfile(
session: nox.Session,
*,
install_args: Sequence[str] = (),
extra_command: Sequence[str] = (),
extra_packages: Sequence[str] = (),
pytest_run_args: Sequence[str] = (),
) -> None:
env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}
"""Run the test suite against a resolution that deviates from the lockfile."""
env = _get_session_env(session)
uv_pip_install = ["uv", "pip", "install", "--python", session.virtualenv.location, *install_args]

if extra_command:
session.run(*extra_command, env=env)
session.run(
"uv",
"run",
"--no-dev",
*uv_pip_install,
"--group",
"test",
*install_args,
"--editable",
".",
env=env,
)
if extra_packages:
session.run(*uv_pip_install, *extra_packages, env=env)
session.run(
"pytest",
*pytest_run_args,
*session.posargs,
Expand All @@ -83,40 +97,34 @@ def _run_tests(
)


@nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, default=True)
def tests(session: nox.Session) -> None:
"""Run the test suite."""
_run_tests(session)


@nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True)
@nox.session(python=PYTHON_VERSIONS, reuse_venv=True, venv_backend="uv", default=True, allow_parallel=True)
def minimums(session: nox.Session) -> None:
"""Test the minimum versions of dependencies."""
with preserve_lockfile():
_run_tests(
session,
install_args=["--resolution=lowest-direct"],
pytest_run_args=["-Wdefault"],
)
env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}
session.run("uv", "tree", "--frozen", env=env)
_run_tests_without_lockfile(
session,
install_args=["--resolution=lowest-direct"],
pytest_run_args=["-Wdefault"],
)
session.run("uv", "pip", "tree", "--python", session.virtualenv.location)


@nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS)
@nox.session(python=PYTHON_VERSIONS, reuse_venv=True, venv_backend="uv")
def qiskit(session: nox.Session) -> None:
"""Tests against the latest version of Qiskit."""
with preserve_lockfile():
_run_tests(
session,
extra_command=["uv", "pip", "install", "qiskit[qasm3-import] @ git+https://github.com/Qiskit/qiskit.git"],
)
env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}
session.run("uv", "pip", "show", "qiskit", env=env)
_run_tests_without_lockfile(
session,
extra_packages=["qiskit[qasm3-import] @ git+https://github.com/Qiskit/qiskit.git"],
)
session.run("uv", "pip", "show", "--python", session.virtualenv.location, "qiskit")


@nox.session(reuse_venv=True)
def docs(session: nox.Session) -> None:
"""Build the docs. Use "--non-interactive" to avoid serving. Pass "-b linkcheck" to check links."""
"""Build the docs.

Use ``--non-interactive`` to avoid serving.
Pass ``-b linkcheck`` to check links.
"""
parser = argparse.ArgumentParser()
parser.add_argument("-b", dest="builder", default="html", help="Build target (default: html)")
args, posargs = parser.parse_known_args(session.posargs)
Expand All @@ -125,16 +133,6 @@ def docs(session: nox.Session) -> None:
if serve:
session.install("sphinx-autobuild")

env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}
shared_args = [
"-n", # nitpicky mode
"-T", # full tracebacks
f"-b={args.builder}",
"docs",
f"docs/_build/{args.builder}",
*posargs,
]

session.run(
"uv",
"run",
Expand All @@ -143,8 +141,13 @@ def docs(session: nox.Session) -> None:
"docs",
"--frozen",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we drop the --frozen here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could. On the other hand, this ensures that a known-good set of versions is used. Could prevent a couple of bad surprises.

"sphinx-autobuild" if serve else "sphinx-build",
*shared_args,
env=env,
"-n", # nitpicky mode
"-T", # full tracebacks
f"-b={args.builder}",
"docs",
f"docs/_build/{args.builder}",
*posargs,
env=_get_session_env(session),
)


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ docs = [
]
dev = [
{include-group = "test"},
"nox>=2025.11.12",
"nox>=2026.08.10",
"prek>=0.2.27",
]

Expand Down
Loading
Loading