Both runtests.sh scripts create their own virtualenv on first run and can be
invoked from any directory -- the paths below are just the convenient way to
type them. The venv is (re)built automatically whenever it is missing or its
-pyproject.toml has changed, using `uv sync` if uv is installed and otherwise
-`python3 -m venv` + pip (reading the dependency list from pyproject.toml -- no
-uv required). To force a clean rebuild yourself, `rm -rf <suite>/.venv`.
+pyproject.toml has changed, using `uv sync` (uv reads pyproject.toml + uv.lock).
+uv (https://docs.astral.sh/uv/) is required. To force a clean rebuild yourself,
+`rm -rf <suite>/.venv`.
pytest_suite (self-contained; the venv holds only pytest + httpx):
Install
-------
-If not already installed, you will need to install 'pytest' and 'OpenSSL' for
-python:
-> apt install python3-pip
-> pip install -U pytest
-> pip install -U pyopenssl
+The Python dependencies (pytest, pyOpenSSL, etc.) are managed with uv
+(https://docs.astral.sh/uv/), which reads pyproject.toml + uv.lock and creates
+a local .venv. Install uv, then let pyhttpd/runtests.sh build the venv on first
+run (it invokes `uv sync` for you); or create it yourself:
+> uv sync
And for 'h2load':
> apt install nghttp2-client
here="$(cd "$(dirname "$0")" && pwd)"
# --- ensure the venv exists and is current ----------------------------------
-# We invoke .venv/bin/pytest directly rather than `uv run` so the suite works
-# even where `uv run` is shimmed/unavailable.
+# The suite baselines on uv (https://docs.astral.sh/uv/) as its dependency and
+# venv manager: it reads pyproject.toml + uv.lock, so there is a single source
+# of truth for dependencies. We invoke .venv/bin/pytest directly rather than
+# `uv run` so the suite works even where `uv run` is shimmed/unavailable.
#
# Create $here/.venv on first run, and rebuild it when pyproject.toml is newer
-# than the venv (i.e. dependencies changed). Prefer uv (which reads
-# pyproject.toml + uv.lock); otherwise fall back to python3 -m venv + pip,
-# taking the dependency list straight from pyproject.toml so there is no second
-# copy to keep in sync. Absolute paths throughout, so this behaves identically
-# regardless of the caller's cwd. This block is kept byte-for-byte identical in
-# pytest_suite/runtests.sh and pyhttpd/runtests.sh -- edit both together.
+# than the venv (i.e. dependencies changed). Absolute paths throughout, so this
+# behaves identically regardless of the caller's cwd. This block is kept
+# byte-for-byte identical in pytest_suite/runtests.sh and pyhttpd/runtests.sh
+# -- edit both together.
PYTEST="$here/.venv/bin/pytest"
if [ ! -x "$PYTEST" ] || [ "$here/pyproject.toml" -nt "$here/.venv" ]; then
- if command -v uv >/dev/null 2>&1; then
- echo "runtests.sh: (re)creating $here/.venv via 'uv sync'..." >&2
- uv sync --project "$here"
- elif command -v python3 >/dev/null 2>&1; then
- echo "runtests.sh: (re)creating $here/.venv via python3 + pip..." >&2
- python3 -m venv "$here/.venv"
- # Read [project].dependencies from pyproject.toml (one entry per line,
- # double-quoted) so the install list never drifts from the manifest.
- deps=$(awk -F'"' '/^dependencies = \[/{f=1; next} f && /^\]/{f=0} f && NF>=2 {print $2}' "$here/pyproject.toml")
- # shellcheck disable=SC2086 # deps is an intentional word-split list
- "$here/.venv/bin/pip" install --quiet $deps
- else
- echo "runtests.sh: ERROR: $PYTEST not found and neither 'uv' nor 'python3' is installed." >&2
+ if ! command -v uv >/dev/null 2>&1; then
+ echo "runtests.sh: ERROR: 'uv' is required but not installed." >&2
+ echo " Install it from https://docs.astral.sh/uv/ and re-run." >&2
exit 1
fi
+ echo "runtests.sh: (re)creating $here/.venv via 'uv sync'..." >&2
+ uv sync --project "$here"
# Mark the venv as freshly built so the staleness check above won't retrigger
# until pyproject.toml changes again.
touch "$here/.venv"
## Quick start
```sh
-# 1. Create the virtualenv (pytest + httpx). Needs `uv` (https://docs.astral.sh/uv/),
-# or substitute a plain venv -- see "Environment" below.
+# 1. Create the virtualenv (pytest + httpx). Needs `uv` (https://docs.astral.sh/uv/);
+# reads pyproject.toml + uv.lock. runtests.sh also does this for you on first run.
uv sync
# 2. Run the whole suite against your httpd build.
cd "$here"
# --- ensure the venv exists and is current ----------------------------------
-# We invoke .venv/bin/pytest directly rather than `uv run` so the suite works
-# even where `uv run` is shimmed/unavailable.
+# The suite baselines on uv (https://docs.astral.sh/uv/) as its dependency and
+# venv manager: it reads pyproject.toml + uv.lock, so there is a single source
+# of truth for dependencies. We invoke .venv/bin/pytest directly rather than
+# `uv run` so the suite works even where `uv run` is shimmed/unavailable.
#
# Create $here/.venv on first run, and rebuild it when pyproject.toml is newer
-# than the venv (i.e. dependencies changed). Prefer uv (which reads
-# pyproject.toml + uv.lock); otherwise fall back to python3 -m venv + pip,
-# taking the dependency list straight from pyproject.toml so there is no second
-# copy to keep in sync. Absolute paths throughout, so this behaves identically
-# regardless of the caller's cwd. This block is kept byte-for-byte identical in
-# pytest_suite/runtests.sh and pyhttpd/runtests.sh -- edit both together.
+# than the venv (i.e. dependencies changed). Absolute paths throughout, so this
+# behaves identically regardless of the caller's cwd. This block is kept
+# byte-for-byte identical in pytest_suite/runtests.sh and pyhttpd/runtests.sh
+# -- edit both together.
PYTEST="$here/.venv/bin/pytest"
if [ ! -x "$PYTEST" ] || [ "$here/pyproject.toml" -nt "$here/.venv" ]; then
- if command -v uv >/dev/null 2>&1; then
- echo "runtests.sh: (re)creating $here/.venv via 'uv sync'..." >&2
- uv sync --project "$here"
- elif command -v python3 >/dev/null 2>&1; then
- echo "runtests.sh: (re)creating $here/.venv via python3 + pip..." >&2
- python3 -m venv "$here/.venv"
- # Read [project].dependencies from pyproject.toml (one entry per line,
- # double-quoted) so the install list never drifts from the manifest.
- deps=$(awk -F'"' '/^dependencies = \[/{f=1; next} f && /^\]/{f=0} f && NF>=2 {print $2}' "$here/pyproject.toml")
- # shellcheck disable=SC2086 # deps is an intentional word-split list
- "$here/.venv/bin/pip" install --quiet $deps
- else
- echo "runtests.sh: ERROR: $PYTEST not found and neither 'uv' nor 'python3' is installed." >&2
+ if ! command -v uv >/dev/null 2>&1; then
+ echo "runtests.sh: ERROR: 'uv' is required but not installed." >&2
+ echo " Install it from https://docs.astral.sh/uv/ and re-run." >&2
exit 1
fi
+ echo "runtests.sh: (re)creating $here/.venv via 'uv sync'..." >&2
+ uv sync --project "$here"
# Mark the venv as freshly built so the staleness check above won't retrigger
# until pyproject.toml changes again.
touch "$here/.venv"