build(m1): pin toolchain and guard v1.3.0 in pyproject
Plan Step 2. Verify green: `bash scripts/bootstrap.sh && .venv/bin/python -m
pytest tests/test_toolchain.py` -> 3 passed, exit 0.
Test first, and the RED was demonstrated rather than assumed: run against a
venv carrying pytest and the guard but not pytest-socket, the third test fails
with ModuleNotFoundError while the other two pass. The test discriminates.
pyproject.toml declares the dependencies as a PEP 735 group rather than an
installable distribution -- nothing here needs a build backend, since the tests
import from scripts/ via pytest's pythonpath. Measured before choosing it: pip
26.2.1 on this machine supports `install --group`, and bootstrap upgrades pip
first, so a pip too old fails loudly instead of silently skipping the guard.
The guard is pinned to the exact tag v1.3.0 and is not vendored. Verified the
tag resolves and the package exposes __version__ == "1.3.0"; that equality is
what the test asserts, not the pip metadata.
addopts carries --disable-socket and --strict-markers, which is why the
`network` marker is declared: with strict markers an undeclared marker would
make `-m 'not network'` an error rather than a filter, and the offline
guarantee would quietly stop being tested.
bootstrap.sh builds under ${CLAUDE_PLUGIN_DATA} when set (survives a plugin
update) and falls back to the repo-root .venv for development -- risk H2. It
refuses an interpreter below 3.10 instead of building on it, because python3
here can resolve to 3.9.6 under a GUI-spawned process.
Exercised, not just written: re-running is idempotent (exit 0); --med-xlsx
installs the extra (openpyxl 3.1.5 importable); an unknown argument exits 2
with usage; a missing JOBBSOK_PYTHON interpreter refuses loudly. bash 3.2-clean
(system /bin/bash 3.2.57 -n passes) and ASCII-only.
.gitignore needed no change: `.venv/` was already on line 12 from the initial
commit, and `git check-ignore -v .venv` confirms it matches.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0f92b2a1c3
commit
24768ef66b
3 changed files with 175 additions and 0 deletions
91
scripts/bootstrap.sh
Executable file
91
scripts/bootstrap.sh
Executable file
|
|
@ -0,0 +1,91 @@
|
|||
#!/bin/bash
|
||||
# Build the jobbsok Python environment and pin the ingestion guard.
|
||||
#
|
||||
# bash 3.2-clean and ASCII-only on purpose: the system bash on this Mac is 3.2,
|
||||
# and a multibyte character has crashed a `set -u` script here before.
|
||||
#
|
||||
# Where the environment lives is load-bearing, not incidental. When
|
||||
# CLAUDE_PLUGIN_DATA is set the environment is built there, because that
|
||||
# directory survives a plugin update -- the plugin's own cache does not. A
|
||||
# repo-root-only .venv would leave every non-development install without the
|
||||
# guard, which is risk H2. The repo-root .venv is the development case.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/bootstrap.sh # dev dependencies
|
||||
# bash scripts/bootstrap.sh --med-xlsx # also the openpyxl extra
|
||||
|
||||
set -eu
|
||||
|
||||
MIN_MAJOR=3
|
||||
MIN_MINOR=10
|
||||
|
||||
WITH_XLSX=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--med-xlsx) WITH_XLSX=1 ;;
|
||||
-h|--help)
|
||||
sed -n '2,20p' "$0"
|
||||
exit 0 ;;
|
||||
*)
|
||||
echo "bootstrap: unknown argument: $arg" >&2
|
||||
echo "bootstrap: usage: bash scripts/bootstrap.sh [--med-xlsx]" >&2
|
||||
exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd)
|
||||
|
||||
if [ -n "${CLAUDE_PLUGIN_DATA:-}" ]; then
|
||||
VENV_DIR="${CLAUDE_PLUGIN_DATA}/venv"
|
||||
VENV_KIND="plugin-data (survives a plugin update)"
|
||||
else
|
||||
VENV_DIR="${REPO_ROOT}/.venv"
|
||||
VENV_KIND="repo root (development)"
|
||||
fi
|
||||
|
||||
# Refuse an interpreter that is too old rather than building an environment
|
||||
# that parses everything and fails at runtime. Under a GUI-spawned process with
|
||||
# an empty PATH, python3 here can resolve to 3.9.6.
|
||||
PYTHON_BIN="${JOBBSOK_PYTHON:-python3}"
|
||||
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
|
||||
echo "bootstrap: no such interpreter: $PYTHON_BIN" >&2
|
||||
echo "bootstrap: set JOBBSOK_PYTHON to a Python ${MIN_MAJOR}.${MIN_MINOR}+ executable." >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! "$PYTHON_BIN" -c "import sys; sys.exit(0 if sys.version_info >= ($MIN_MAJOR, $MIN_MINOR) else 1)"; then
|
||||
FOUND=$("$PYTHON_BIN" -c "import sys; print('%d.%d.%d' % sys.version_info[:3])")
|
||||
echo "bootstrap: $PYTHON_BIN is Python $FOUND; ${MIN_MAJOR}.${MIN_MINOR}+ is required." >&2
|
||||
echo "bootstrap: refusing to build an environment on it. Set JOBBSOK_PYTHON instead." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "bootstrap: interpreter $("$PYTHON_BIN" -c 'import sys; print(sys.executable)')"
|
||||
echo "bootstrap: environment $VENV_DIR [$VENV_KIND]"
|
||||
|
||||
if [ ! -x "${VENV_DIR}/bin/python" ]; then
|
||||
mkdir -p "$(dirname "$VENV_DIR")"
|
||||
"$PYTHON_BIN" -m venv "$VENV_DIR"
|
||||
fi
|
||||
|
||||
VENV_PY="${VENV_DIR}/bin/python"
|
||||
|
||||
"$VENV_PY" -m pip install --quiet --upgrade pip
|
||||
# PEP 735 dependency groups need pip 25.1+; the upgrade above is what makes
|
||||
# this line safe, and a pip too old to understand --group fails loudly here.
|
||||
"$VENV_PY" -m pip install --quiet --group "${REPO_ROOT}/pyproject.toml:dev"
|
||||
if [ "$WITH_XLSX" -eq 1 ]; then
|
||||
"$VENV_PY" -m pip install --quiet --group "${REPO_ROOT}/pyproject.toml:xlsx"
|
||||
fi
|
||||
|
||||
"$VENV_PY" - <<'PYEOF'
|
||||
import sys
|
||||
|
||||
import llm_ingestion_guard
|
||||
|
||||
print("bootstrap: sys.executable %s" % sys.executable)
|
||||
print("bootstrap: python %s" % sys.version.split()[0])
|
||||
print("bootstrap: guard %s" % llm_ingestion_guard.__version__)
|
||||
PYEOF
|
||||
|
||||
echo "bootstrap: ok"
|
||||
Loading…
Add table
Add a link
Reference in a new issue