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 diff --git a/.github/.lambda-python-runtimes b/.github/.lambda-python-runtimes new file mode 100644 index 0000000..b0a9286 --- /dev/null +++ b/.github/.lambda-python-runtimes @@ -0,0 +1,7 @@ +3.9 +3.10 +3.11 +3.12 +3.13 +3.14 +3.15 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 }} 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()