From 318ab2656bef8d1cf6366af484b9e5ba11576ff9 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Wed, 19 Aug 2026 18:38:44 -0400 Subject: [PATCH] fix: tombstone build needs setuptools installed explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TestPyPI rehearsal (run 32309423898) failed before uploading anything: the sdist builds with --no-isolation, and Python 3.12 dropped setuptools from the default environment, so the runner had no build backend. It surfaced as `BackendUnavailable: Cannot import 'setuptools.build_meta'` from inside pyproject_hooks — naming neither the cause nor the fix. It did not reproduce locally because this machine's 3.12 happens to carry setuptools. A bare 3.12 venv does not, which is the runner's condition. - publish_tombstone.yml installs setuptools explicitly. - build_sdist() checks for the backend first and says what to install, so the next environment without it gets an answer instead of a stack trace. - A test pins the precondition. Verified in a bare 3.12 venv (the runner's condition): the check fires with the clear message, and with setuptools installed all five sdists build and `twine check` passes on every one. Issue: https://github.com/PyAutoLabs/PyAutoHands/issues/238 Co-Authored-By: Claude Opus 5 --- .github/workflows/publish_tombstone.yml | 5 ++++- autohands/tombstone.py | 23 +++++++++++++++++++++++ tests/test_tombstone.py | 13 +++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish_tombstone.yml b/.github/workflows/publish_tombstone.yml index d078e25..6020a0c 100644 --- a/.github/workflows/publish_tombstone.yml +++ b/.github/workflows/publish_tombstone.yml @@ -54,7 +54,10 @@ jobs: - name: Build the tombstone sdists run: | - python3 -m pip install --upgrade build twine==6.0.1 + # setuptools is explicit: the sdist builds with --no-isolation, and + # Python 3.12+ runners no longer ship setuptools, so the backend + # would otherwise be missing (BackendUnavailable, run 32309423898). + python3 -m pip install --upgrade build twine==6.0.1 setuptools python3 -m autohands.tombstone --out dist-tombstone - name: Check metadata diff --git a/autohands/tombstone.py b/autohands/tombstone.py index f0c6a82..3fcd128 100644 --- a/autohands/tombstone.py +++ b/autohands/tombstone.py @@ -67,6 +67,7 @@ from __future__ import annotations import argparse +import importlib.util import shutil import subprocess import sys @@ -251,6 +252,27 @@ def write_project( return project_dir +def require_setuptools() -> None: + """Fail early, and legibly, when the build backend is missing. + + The sdist is built with `--no-isolation`, so setuptools has to be present in + this interpreter — and Python 3.12 dropped it from the default environment. + Without this check the failure surfaces as `BackendUnavailable: Cannot + import 'setuptools.build_meta'` from inside pyproject_hooks, which names + neither the cause nor the fix. A developer machine that happens to have + setuptools installed will not reproduce it, so the check has to be explicit + rather than left to whatever the environment happens to carry. + """ + if importlib.util.find_spec("setuptools") is None: + raise RuntimeError( + "setuptools is not installed in this interpreter, so the sdist cannot " + "be built. The build deliberately runs with --no-isolation so it " + "cannot silently reach the network for a backend; Python 3.12 and " + "later no longer ship setuptools by default. Install it first: " + "python3 -m pip install setuptools" + ) + + def build_sdist( project_dir: Path, out_dir: Path, @@ -268,6 +290,7 @@ def build_sdist( so "the newest tarball here" would happily hand back a sibling package's sdist and verify *its* metadata instead. """ + require_setuptools() out_dir.mkdir(parents=True, exist_ok=True) subprocess.run( [ diff --git a/tests/test_tombstone.py b/tests/test_tombstone.py index 882fd1b..7ea36ba 100644 --- a/tests/test_tombstone.py +++ b/tests/test_tombstone.py @@ -163,6 +163,19 @@ def _build_available(): ) +def test_missing_setuptools_is_reported_before_the_build(tmp_path, monkeypatch): + """`--no-isolation` means the backend must already be installed, and Python + 3.12 dropped setuptools from the default environment. Left unchecked the + failure arrives as `BackendUnavailable: Cannot import + 'setuptools.build_meta'` from inside pyproject_hooks, naming neither the + cause nor the fix — and a machine that happens to have setuptools will + never reproduce it (PyAutoHands run 32309423898).""" + monkeypatch.setattr(tombstone.importlib.util, "find_spec", lambda name: None) + + with pytest.raises(RuntimeError, match="pip install setuptools"): + tombstone.build_sdist(tmp_path / "project", tmp_path / "dist", "autolens") + + @requires_build def test_built_sdist_declares_sub_floor_requires_python(tmp_path): project = tombstone.write_project("autolens", tmp_path)