From c892b835c98106dbaaf00f1e3c510732541c7c20 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Thu, 6 Nov 2025 10:25:25 +0100 Subject: [PATCH 1/3] chore(toxgen): Check availability of pip and add detail to exceptions --- scripts/populate_tox/populate_tox.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/scripts/populate_tox/populate_tox.py b/scripts/populate_tox/populate_tox.py index 2d81a85ea2..00c12c1544 100644 --- a/scripts/populate_tox/populate_tox.py +++ b/scripts/populate_tox/populate_tox.py @@ -890,7 +890,31 @@ def _normalize_package_dependencies(package_dependencies: list[dict]) -> list[di def _exit_if_not_free_threaded_interpreter(): if "free-threading build" not in sys.version: - raise Exception("Running with a free-threaded interpreter is required.") + exc = Exception("Running with a free-threaded interpreter is required.") + exc.add_note( + "A dry run of pip is used to determine free-threading support of integrations." + ) + raise exc + + +def _exit_if_pip_unavailable(): + pip_help_return_code = subprocess.run( + [ + sys.executable, + "-m", + "pip", + "--help", + ], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ).returncode + + if pip_help_return_code != 0: + exc = Exception("pip must be available.") + exc.add_note( + "A dry run of pip is used to determine free-threading support of integrations." + ) + raise exc def main() -> dict[str, list]: @@ -900,6 +924,7 @@ def main() -> dict[str, list]: global MIN_PYTHON_VERSION, MAX_PYTHON_VERSION _exit_if_not_free_threaded_interpreter() + _exit_if_pip_unavailable() meta = _fetch_sdk_metadata() sdk_python_versions = _parse_python_versions_from_classifiers( From 908fd907d6aecbde0ccc273ec7f022d80d417c67 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Thu, 6 Nov 2025 10:26:10 +0100 Subject: [PATCH 2/3] . --- scripts/populate_tox/populate_tox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/populate_tox/populate_tox.py b/scripts/populate_tox/populate_tox.py index 00c12c1544..df8495e58f 100644 --- a/scripts/populate_tox/populate_tox.py +++ b/scripts/populate_tox/populate_tox.py @@ -892,7 +892,7 @@ def _exit_if_not_free_threaded_interpreter(): if "free-threading build" not in sys.version: exc = Exception("Running with a free-threaded interpreter is required.") exc.add_note( - "A dry run of pip is used to determine free-threading support of integrations." + "A dry run of pip is used to determine free-threading support of packages." ) raise exc @@ -912,7 +912,7 @@ def _exit_if_pip_unavailable(): if pip_help_return_code != 0: exc = Exception("pip must be available.") exc.add_note( - "A dry run of pip is used to determine free-threading support of integrations." + "A dry run of pip is used to determine free-threading support of packages." ) raise exc From 993a7705422db1e4fad9854c98e85f2338264b6e Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Thu, 6 Nov 2025 10:49:13 +0100 Subject: [PATCH 3/3] doc --- scripts/populate_tox/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/populate_tox/README.md b/scripts/populate_tox/README.md index d6c4e52147..e483ed78cb 100644 --- a/scripts/populate_tox/README.md +++ b/scripts/populate_tox/README.md @@ -7,6 +7,20 @@ sure we support everything we claim to. This `populate_tox.py` script is responsible for picking reasonable versions to test automatically and generating parts of `tox.ini` to capture this. +## Running the script + +You require a free-threaded interpreter with pip installed to run the script. With +a recent version of `uv` you can directly run the script with the following +command: + +``` +uv run --python 3.14t \ + --with pip \ + --with-requirements scripts/populate_tox/requirements.txt \ + --with-editable . \ + python scripts/populate_tox/populate_tox.py +``` + ## How it works There is a template in this directory called `tox.jinja` which contains a