Pular para o conteúdo

Nox Cheat Sheet

Overview

Nox is a Python test automation tool similar to tox but uses Python scripts (noxfile.py) instead of configuration files. This approach provides full Python expressiveness for defining test sessions, including conditionals, loops, and function composition. Nox is used by many Google open-source Python projects.

Nox creates isolated virtual environments for each session, installs dependencies, and runs commands. Its Python-based configuration makes it easier to handle complex testing scenarios, dynamic dependency resolution, and conditional session logic compared to INI-based alternatives.

Installation

pip install nox
# or
pipx install nox

# Verify
nox --version

Core Commands

CommandDescription
noxRun all default sessions
nox -s testsRun specific session
nox -s tests-3.12Run parametrized session
nox -lList available sessions
nox -rReuse existing virtualenvs
nox --no-venvSkip virtualenv creation
nox -k "not lint"Filter sessions by keyword
nox --forcecolorForce colored output

Configuration

Basic noxfile.py

import nox

@nox.session
def tests(session):
    """Run the test suite."""
    session.install("pytest", "pytest-cov")
    session.install(".")
    session.run("pytest", "tests/", "-v")

@nox.session
def lint(session):
    """Run linters."""
    session.install("ruff")
    session.run("ruff", "check", "src/", "tests/")

@nox.session
def typecheck(session):
    """Run type checking."""
    session.install("mypy", "types-requests")
    session.install(".")
    session.run("mypy", "src/")

@nox.session
def docs(session):
    """Build documentation."""
    session.install("mkdocs", "mkdocs-material")
    session.run("mkdocs", "build")

Parametrized Sessions

import nox

@nox.session(python=["3.10", "3.11", "3.12"])
def tests(session):
    """Run tests across Python versions."""
    session.install("pytest", ".")
    session.run("pytest")

@nox.parametrize("django", ["4.2", "5.0"])
@nox.session(python=["3.11", "3.12"])
def test_django(session, django):
    """Test against multiple Django versions."""
    session.install(f"django=={django}", "pytest", "pytest-django", ".")
    session.run("pytest", "tests/")

Reusable Sessions

import nox

def install_deps(session):
    """Helper to install common dependencies."""
    session.install("-r", "requirements.txt")
    session.install("-r", "requirements-dev.txt")
    session.install("-e", ".")

@nox.session
def tests(session):
    install_deps(session)
    session.run("pytest", *session.posargs)

@nox.session
def coverage(session):
    install_deps(session)
    session.run("pytest", "--cov=src", "--cov-report=html")

Advanced Usage

Conditional Sessions

import nox
import os

@nox.session
def tests(session):
    session.install("pytest", ".")
    args = ["pytest"]
    if os.environ.get("CI"):
        args.extend(["--tb=short", "-q"])
    else:
        args.extend(["-v", "--tb=long"])
    session.run(*args)

@nox.session
def deploy(session):
    """Deploy only on main branch."""
    if os.environ.get("GITHUB_REF") != "refs/heads/main":
        session.skip("Only deploy from main branch")
    session.install("twine")
    session.run("twine", "upload", "dist/*")

Session Options

@nox.session(
    python="3.12",
    reuse_venv=True,
    tags=["ci"],
    venv_backend="virtualenv",
)
def fast_tests(session):
    session.install("pytest", ".")
    session.run("pytest", "-x", "--tb=short")

# Use conda instead of venv
@nox.session(venv_backend="conda")
def conda_tests(session):
    session.conda_install("numpy", "pandas")
    session.install(".")
    session.run("pytest")

Tags and Filtering

@nox.session(tags=["lint"])
def ruff(session):
    session.install("ruff")
    session.run("ruff", "check", ".")

@nox.session(tags=["lint"])
def mypy(session):
    session.install("mypy", ".")
    session.run("mypy", "src/")

@nox.session(tags=["test"])
def unit(session):
    session.install("pytest", ".")
    session.run("pytest", "tests/unit/")

@nox.session(tags=["test"])
def integration(session):
    session.install("pytest", ".")
    session.run("pytest", "tests/integration/")
# Run by tag
nox -t lint
nox -t test

# Run by keyword
nox -k "not integration"

Default Sessions

# Set which sessions run by default
nox.options.sessions = ["tests", "lint"]
nox.options.reuse_existing_virtualenvs = True
nox.options.default_venv_backend = "virtualenv"

Troubleshooting

IssueSolution
Python version not foundInstall it; use nox -s tests-3.12 syntax
Session skippedCheck nox -l for available sessions
Slow venv creationUse nox -r to reuse existing environments
Import errorEnsure session.install(".") is called
posargs not passingUse nox -- -x -v (args after --)
# List sessions
nox -l

# Reuse virtualenvs (faster)
nox -r -s tests

# Pass arguments to test runner
nox -s tests -- -x -v tests/test_specific.py

# Force recreate virtualenvs
nox -s tests --forcecolor

# Verbose
nox -v -s tests