Testing different Python versions with uv with-editable and uv-test

A quick uv recipe I figured out today, for running the tests for a project against multiple Python versions.

The key command option is uv run --with-editable .[test].

Start with any Python project that has a [test] extra defined, for example:

cd /tmp
git clone https://github.com/simonw/datasette
cd datasette

Then run uv against it with a specific Python version like this:

uv run --python 3.14 --isolated --with-editable '.[test]' pytest -n auto

Here I'm using --isolated to make sure nothing from any other environments sneaks in.

The --with-editable '.[test]' part is important - it tells uv to install the current project in editable mode so that changes you make will be picked up. I first tried this using --with '.[test]' and was confused as to why changes I made to the code weren't being picked up when I re-ran the tests.

Datasette uses pytest-xdist to run tests in parallel, so I added -n auto to have it automatically use all available CPU cores.

uv-test

I wrote a little helper script (with ChatGPT's help) to make this easier to remember. It uses Python 3.14 by default but you can pass a different version as the -p argument. Any subsequent arguments will be passed to pytest.

#!/bin/sh
set -eu  # (no pipefail in POSIX sh)

usage() {
  echo "Usage: uv-test [-p|--python PY_VER] [pytest args...]"
  echo "  -p, --python  Set Python version (default: \$UV_PY or 3.14)"
  echo "  -h, --help    Show this help"
}

PYVER="${UV_PY:-3.14}"

# Parse only our flags; pass the rest to pytest
while [ $# -gt 0 ]; do
  case "$1" in
    -p|--python)
      shift
      [ $# -gt 0 ] || { echo "error: -p/--python requires a version" >&2; exit 2; }
      PYVER="$1"; shift ;;
    -h|--help) usage; exit 0 ;;
    --) shift; break ;;
    *) break ;;
  esac
done

command -v uv >/dev/null 2>&1 || { echo "error: 'uv' not found in PATH" >&2; exit 127; }
if [ ! -f pyproject.toml ] && [ ! -f setup.py ]; then
  echo "error: no project file found (need pyproject.toml or setup.py). Run from project root." >&2
  exit 1
fi

exec uv run --python "$PYVER" --isolated --with-editable '.[test]' -- python -m pytest "$@"

Make it executable and put it somewhere in your PATH, then you can run it like this:

uv-test

Or for a specific Python version:

uv-test -p 3.13

And for custom pytest arguments:

uv-test -k permissions

Or combined:

uv-test -p 3.12 -k permissions -vv

Created 2025-10-08T19:47:48-07:00, updated 2025-10-08T20:21:33-07:00 · History · Edit