From cbe0abcaf44dce3889d41a1dfe19bad3963ade7a Mon Sep 17 00:00:00 2001
From: generaltony007 <191973953+hakarrr@users.noreply.github.com>
Date: Wed, 11 Nov 2026 02:55:31 +0530
Subject: [PATCH 1/4] fix(index): include available SHA256 hashes in wheel
links
Use valid release-asset digests while preserving links for assets without usable SHA256 values.
Co-authored-by: GeneralTony007 <144252170+GeneralTony007@users.noreply.github.com>
---
scripts/releases-to-pep-503.sh | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/scripts/releases-to-pep-503.sh b/scripts/releases-to-pep-503.sh
index 835962449..bdcf094c8 100755
--- a/scripts/releases-to-pep-503.sh
+++ b/scripts/releases-to-pep-503.sh
@@ -85,8 +85,12 @@ for release in $releases; do
continue
fi
- wheel_urls=$(echo "$response" | jq -r '.assets[] | select(.name | endswith(".whl")) | .browser_download_url')
- if [ -z "$wheel_urls" ]; then
+ wheel_assets=$(echo "$response" | jq -r '
+ .assets[] | select(.name | endswith(".whl")) |
+ [.browser_download_url,
+ (if (.digest | type) == "string" then .digest else "" end)] | @tsv
+ ')
+ if [ -z "$wheel_assets" ]; then
log_error "No wheel files found for release $release"
continue
fi
@@ -95,8 +99,12 @@ for release in $releases; do
release_version=$(echo "$release" | grep -oE "^[v]?[0-9]+\.[0-9]+\.[0-9]+")
echo "
$release_version
" >> "$output_dir/llama-cpp-python/index.html"
- echo "$wheel_urls" | while read -r asset; do
- echo " $asset" >> "$output_dir/llama-cpp-python/index.html"
+ echo "$wheel_assets" | while IFS=$'\t' read -r asset digest; do
+ href="$asset"
+ if [[ "$digest" =~ ^sha256:([[:xdigit:]]{64})$ ]]; then
+ href="$asset#sha256=${BASH_REMATCH[1]}"
+ fi
+ echo " $asset" >> "$output_dir/llama-cpp-python/index.html"
echo "
" >> "$output_dir/llama-cpp-python/index.html"
done
done
From 96ce03d3ec7ade7f70ff71c27815b7f476a8294f Mon Sep 17 00:00:00 2001
From: generaltony007 <191973953+hakarrr@users.noreply.github.com>
Date: Wed, 11 Nov 2026 02:56:00 +0530
Subject: [PATCH 2/4] test(index): cover release-asset digests and legacy links
Exercise the real shell generator with offline release JSON fixtures, including missing and unusable digests, mixed assets, backend filters, and empty indexes.
Co-authored-by: GeneralTony007 <144252170+GeneralTony007@users.noreply.github.com>
---
tests/test_release_index.py | 130 ++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 tests/test_release_index.py
diff --git a/tests/test_release_index.py b/tests/test_release_index.py
new file mode 100644
index 000000000..347186db6
--- /dev/null
+++ b/tests/test_release_index.py
@@ -0,0 +1,130 @@
+"""Exercise the release-index generator without downloading release assets."""
+
+import json
+import os
+from pathlib import Path
+import shutil
+import subprocess
+from html.parser import HTMLParser
+
+import pytest
+
+
+SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "releases-to-pep-503.sh"
+WHEEL_URL = "https://example.invalid/llama_cpp_python-0.3.36-py3-none-any.whl"
+SHA256 = "0123456789abcdef" * 4
+
+
+class Links(HTMLParser):
+ def __init__(self):
+ super().__init__()
+ self.hrefs = []
+
+ def handle_starttag(self, tag, attrs):
+ if tag == "a":
+ self.hrefs.append(dict(attrs)["href"])
+
+
+@pytest.fixture
+def generate_index(tmp_path):
+ for tool in ("bash", "jq"):
+ if shutil.which(tool) is None:
+ pytest.skip(f"release-index tests require {tool}")
+ bin_dir = tmp_path / "bin"
+ bin_dir.mkdir()
+ curl = bin_dir / "curl"
+ curl.write_text('#!/bin/sh\ncat "$RELEASE_RESPONSE"\n')
+ curl.chmod(0o755)
+ response = tmp_path / "response.json"
+ env = {
+ **os.environ,
+ "PATH": f"{bin_dir}{os.pathsep}{os.environ['PATH']}",
+ "RELEASE_RESPONSE": str(response),
+ }
+
+ def run(assets, releases="v0.3.36\n", pattern=None):
+ response.write_text(json.dumps({"assets": assets}))
+ (tmp_path / "all_releases.txt").write_text(releases)
+ output = tmp_path / "index"
+ command = ["bash", str(SCRIPT), str(output)]
+ if pattern is not None:
+ command.append(pattern)
+ subprocess.run(command, cwd=tmp_path, env=env, check=True, capture_output=True)
+ page = (output / "llama-cpp-python" / "index.html").read_text()
+ parser = Links()
+ parser.feed(page)
+ return parser.hrefs, page
+
+ return run
+
+
+def wheel(**kwargs):
+ return {
+ "name": "llama_cpp_python-0.3.36-py3-none-any.whl",
+ "browser_download_url": WHEEL_URL,
+ **kwargs,
+ }
+
+
+@pytest.mark.parametrize("digest", [f"sha256:{SHA256}", f"sha256:{SHA256.upper()}"])
+def test_available_sha256_digest(generate_index, digest):
+ links, page = generate_index([wheel(digest=digest)])
+ assert links == [f"{WHEEL_URL}#sha256={digest.split(':')[1]}"]
+ assert f">{WHEEL_URL}" in page
+
+
+@pytest.mark.parametrize(
+ "digest",
+ [
+ None,
+ "",
+ "sha256:abc",
+ "sha256:" + "z" * 64,
+ "sha512:" + "a" * 128,
+ "sha256:" + SHA256 + "extra",
+ 123,
+ False,
+ {},
+ [],
+ ],
+)
+def test_unusable_digest_preserves_original_link(generate_index, digest):
+ links, _ = generate_index([wheel(digest=digest)])
+ assert links == [WHEEL_URL]
+
+
+def test_historical_asset_without_digest(generate_index):
+ links, _ = generate_index([wheel()])
+ assert links == [WHEEL_URL]
+
+
+def test_mixed_release_assets(generate_index):
+ legacy_url = WHEEL_URL.replace("py3-none-any", "cp311-cp311-linux_x86_64")
+ assets = [
+ wheel(digest=f"sha256:{SHA256}"),
+ {**wheel(), "browser_download_url": legacy_url},
+ {
+ "name": "source.tar.gz",
+ "browser_download_url": "https://example.invalid/source.tar.gz",
+ "digest": f"sha256:{SHA256}",
+ },
+ ]
+ links, _ = generate_index(assets)
+ assert links == [f"{WHEEL_URL}#sha256={SHA256}", legacy_url]
+
+
+def test_backend_release_pattern(generate_index):
+ links, page = generate_index(
+ [wheel(digest=f"sha256:{SHA256}")],
+ releases="v0.3.36\nv0.3.36-cu130\n",
+ pattern=r"^[v]?[0-9]+\.[0-9]+\.[0-9]+-cu130$",
+ )
+ assert links == [f"{WHEEL_URL}#sha256={SHA256}"]
+ assert "v0.3.36
" in page
+
+
+@pytest.mark.parametrize("assets,releases", [([], "v0.3.36\n"), ([wheel()], "")])
+def test_empty_indexes_still_generate(generate_index, assets, releases):
+ links, page = generate_index(assets, releases=releases)
+ assert links == []
+ assert page.rstrip().endswith("