From b031f67e412fa408252d7d81f5744b76d09eff2a Mon Sep 17 00:00:00 2001 From: Gudsfile Date: Thu, 18 Jun 2026 20:28:23 +0200 Subject: [PATCH 1/5] ci(): check PYTHON_VERSIONS against DuckDB wheels and Lambda runtimes Add a pull_request workflow that fails if PYTHON_VERSIONS in build-layer.yml diverges from the intersection of DuckDB manylinux wheels (from PyPI) and supported Lambda runtimes (.github/.lambda-python-runtimes). Catches both missing versions (DuckDB added a Python not in the matrix) and stale versions (DuckDB dropped a Python still in the matrix or a Lambda runtime was removed). Lambda runtimes are hardcoded in .github/.lambda-python-runtimes and must be updated manually when AWS announces a new runtime. Print an error when the DuckDB version in .duckdb-version does not exist on PyPI instead of crashing with an unhandled HTTPError. --- .github/.lambda-python-runtimes | 6 ++ .github/workflows/check-python-versions.yml | 24 ++++++ scripts/check_python_versions.py | 81 +++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 .github/.lambda-python-runtimes create mode 100644 .github/workflows/check-python-versions.yml create mode 100644 scripts/check_python_versions.py diff --git a/.github/.lambda-python-runtimes b/.github/.lambda-python-runtimes new file mode 100644 index 0000000..c6a9edf --- /dev/null +++ b/.github/.lambda-python-runtimes @@ -0,0 +1,6 @@ +3.9 +3.10 +3.11 +3.12 +3.13 +3.14 diff --git a/.github/workflows/check-python-versions.yml b/.github/workflows/check-python-versions.yml new file mode 100644 index 0000000..0e0032e --- /dev/null +++ b/.github/workflows/check-python-versions.yml @@ -0,0 +1,24 @@ +name: Check Python versions matrix + +on: + pull_request: + paths: + - ".github/.duckdb-version" + - ".github/.lambda-python-runtimes" + - ".github/workflows/build-layer.yml" + +jobs: + check: + name: Check PYTHON_VERSIONS against DuckDB wheels and Lambda runtimes + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.x" + + - name: Check PYTHON_VERSIONS + run: python scripts/check_python_versions.py diff --git a/scripts/check_python_versions.py b/scripts/check_python_versions.py new file mode 100644 index 0000000..3ed5e91 --- /dev/null +++ b/scripts/check_python_versions.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +import json +import re +import sys +import urllib.error +import urllib.request +from pathlib import Path + +repo_root = Path(__file__).parent.parent + + +def fetch_duckdb_pythons(version: str) -> set[str]: + url = f"https://pypi.org/pypi/duckdb/{version}/json" + try: + with urllib.request.urlopen(url) as response: + data = json.load(response) + except urllib.error.HTTPError as e: + if e.code == 404: + print(f"Error: DuckDB {version} not found on PyPI.", file=sys.stderr) + else: + print( + f"Error: PyPI returned HTTP {e.code} for DuckDB {version}.", + file=sys.stderr, + ) + sys.exit(1) + pythons = set() + for file in data["urls"]: + filename = file["filename"] + if "manylinux" not in filename: + continue + match = re.search(r"cp3(\d+)", filename) + if match: + pythons.add(f"3.{match.group(1)}") + return pythons + + +def read_lambda_runtimes() -> set[str]: + path = repo_root / ".github" / ".lambda-python-runtimes" + return {line.strip() for line in path.read_text().splitlines() if line.strip()} + + +def read_python_versions() -> set[str]: + path = repo_root / ".github" / "workflows" / "build-layer.yml" + match = re.search(r'PYTHON_VERSIONS:\s*"([^"]+)"', path.read_text()) + if not match: + print("Error: PYTHON_VERSIONS not found in build-layer.yml", file=sys.stderr) + sys.exit(1) + return {v.strip() for v in match.group(1).split(",")} + + +def main(): + duckdb_version = (repo_root / ".github" / ".duckdb-version").read_text().strip() + + duckdb_pythons = fetch_duckdb_pythons(duckdb_version) + lambda_runtimes = read_lambda_runtimes() + current = read_python_versions() + expected = duckdb_pythons & lambda_runtimes + + if expected == current: + print(f"PYTHON_VERSIONS is correct for DuckDB {duckdb_version}.") + return + + def ver_key(v: str) -> tuple: + return tuple(int(x) for x in v.split(".")) + + print(f"PYTHON_VERSIONS mismatch for DuckDB {duckdb_version}:") + for v in sorted(expected - current, key=ver_key): + print(f" + {v} (add to PYTHON_VERSIONS)") + for v in sorted(current - expected, key=ver_key): + if v not in duckdb_pythons and v not in lambda_runtimes: + reason = "not in DuckDB wheels and not in Lambda runtimes, remove from PYTHON_VERSIONS" + elif v not in duckdb_pythons: + reason = "not in DuckDB wheels, remove from PYTHON_VERSIONS" + else: + reason = "not in Lambda runtimes, remove from PYTHON_VERSIONS or update .github/.lambda-python-runtimes" + print(f" - {v} ({reason})") + sys.exit(1) + + +if __name__ == "__main__": + main() From 11975a652bb2b36cd949ad53f206137211020751 Mon Sep 17 00:00:00 2001 From: Gudsfile Date: Sun, 21 Jun 2026 18:03:22 +0200 Subject: [PATCH 2/5] test(fail): Missing Python Version for DuckDB wheel --- .github/.duckdb-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.duckdb-version b/.github/.duckdb-version index 8af85be..9df886c 100644 --- a/.github/.duckdb-version +++ b/.github/.duckdb-version @@ -1 +1 @@ -1.5.3 +1.4.2 From df87d762b63e703539d64b1d565a3d45513b4eab Mon Sep 17 00:00:00 2001 From: Gudsfile Date: Sun, 21 Jun 2026 18:06:29 +0200 Subject: [PATCH 3/5] test(pass): Extra lambda runtime are ignored --- .github/.duckdb-version | 2 +- .github/.lambda-python-runtimes | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/.duckdb-version b/.github/.duckdb-version index 9df886c..8af85be 100644 --- a/.github/.duckdb-version +++ b/.github/.duckdb-version @@ -1 +1 @@ -1.4.2 +1.5.3 diff --git a/.github/.lambda-python-runtimes b/.github/.lambda-python-runtimes index c6a9edf..b0a9286 100644 --- a/.github/.lambda-python-runtimes +++ b/.github/.lambda-python-runtimes @@ -4,3 +4,4 @@ 3.12 3.13 3.14 +3.15 From 5354cb68ffd81f73ed41e5a833a45c9fd91503d7 Mon Sep 17 00:00:00 2001 From: Gudsfile Date: Sun, 21 Jun 2026 18:09:12 +0200 Subject: [PATCH 4/5] test(fail): extra Python Version for DuckDB wheel --- .github/workflows/build-layer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-layer.yml b/.github/workflows/build-layer.yml index efd8feb..11660ee 100644 --- a/.github/workflows/build-layer.yml +++ b/.github/workflows/build-layer.yml @@ -14,7 +14,7 @@ on: #### ENV VARIABLES env: ARCHITECTURES: "x86_64,arm64" - PYTHON_VERSIONS: "3.10,3.11,3.12,3.13,3.14" + PYTHON_VERSIONS: "3.10,3.11,3.12,3.13,3.14,3.15" AWS_REGIONS: ${{ vars.AWS_REGIONS }} AWS_ACCOUNT_ID: ${{ vars.AWS_ACCOUNT_ID }} From 716a5e9e6b6485d70b2fafa06c5e48ee69f770f3 Mon Sep 17 00:00:00 2001 From: Gudsfile Date: Sun, 21 Jun 2026 18:26:46 +0200 Subject: [PATCH 5/5] test(fail): unknown DuckDB version --- .github/.duckdb-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.duckdb-version b/.github/.duckdb-version index 8af85be..fe2f629 100644 --- a/.github/.duckdb-version +++ b/.github/.duckdb-version @@ -1 +1 @@ -1.5.3 +1.5.44