User Guide¶
liblaf.nox_recipes is a small collection of helpers for writing tidy,
repeatable nox sessions. The package stays close to the tools it wraps:
uv still resolves and installs dependencies, pytest still runs your test
suite, and pynvml still decides whether CUDA is available. The helpers exist
to keep that wiring in one place instead of repeating it across every project.
This design is close to the style used by attrs: lead with regular Python,
keep the surface area small, and let the documentation explain how the pieces
fit together.
Start With setup_uv()¶
For most projects, setup_uv() is the only environment bootstrap helper you
need. See the uv helper reference for the full API. It
does four things:
- Compiles a constraints file from
pyproject.toml. - Compiles the requested dependency groups against those constraints.
- Syncs the session environment from the compiled requirements file.
- Installs the current project in editable mode.
from typing import Any
import nox
from liblaf import nox_recipes as recipes
from liblaf.nox_recipes import Resolution
PYPROJECT: dict[str, Any] = nox.project.load_toml("pyproject.toml")
PYTHON_VERSIONS: list[str] = nox.project.python_versions(PYPROJECT)
@nox.session(python=PYTHON_VERSIONS, reuse_venv=True)
@nox.parametrize(
"resolution",
[
nox.param(Resolution.HIGHEST, id="highest"),
nox.param(Resolution.LOWEST_DIRECT, id="lowest-direct"),
],
)
def test(s: nox.Session, resolution: Resolution) -> None:
recipes.setup_uv(s, groups=["test"], resolution=resolution)
recipes.pytest(s, suppress_no_test_exit_code=True)
If you need more control, drop down to the lower-level helpers:
uv_pip_compile(), uv_pip_sync(), and uv_pip_install().
Resolution Strategies¶
Resolution exposes the resolution modes supported by uv. The
uv helper reference documents each option in detail:
| Value | Meaning |
|---|---|
Resolution.HIGHEST |
Prefer the newest compatible versions. |
Resolution.LOWEST |
Prefer the oldest compatible versions across the graph. |
Resolution.LOWEST_DIRECT |
Prefer the oldest direct requirements while keeping transitive resolution practical. |
highest is a good default for everyday development. The lower-bound strategies
are useful when you want CI coverage across older supported dependency ranges.
Running Tests¶
Use pytest() for normal test runs and pytest_bench() for benchmark
sessions. The pytest helper reference covers the
individual parameters.
@nox.session(reuse_venv=True)
def test(s: nox.Session) -> None:
recipes.setup_uv(s, groups=["test"])
recipes.pytest(s, suppress_no_test_exit_code=True)
@nox.session(reuse_venv=True)
def bench(s: nox.Session) -> None:
recipes.setup_uv(s, groups=["test"])
recipes.pytest_bench(s)
Both helpers forward s.posargs so nox -s test -- -k smoke still behaves as
you expect. They also accept an env mapping for per-session environment
variables.
Optional CUDA Sessions¶
GPU-only sessions should be easy to skip on laptops and required on GPU
runners. supports_cuda() is the small guard for that. The
CUDA helper reference covers the underlying detection
helpers.
@nox.session(tags=["gpu"])
def smoke_cuda(s: nox.Session) -> None:
if not recipes.supports_cuda():
s.skip("CUDA driver not available")
recipes.setup_uv(s, groups=["test"])
s.run("python", "-c", "print('CUDA is available')")
If you need to compare against a minimum driver requirement, pass the version
integer returned by cuda_driver_version().
Which Helper Should I Reach For?¶
- Start with
setup_uv()unless you know you need finer-grained control. - Use
pytest()for regular test sessions. - Use
pytest_bench()for CodSpeed-style benchmark runs. - Use
pytest_plugin_versions()when session behavior depends on which pytest plugins are installed. - Use
supports_cuda()to gate optional GPU jobs.