From da7cbfb8f2fa946372fd71ba69540d91004964a5 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Wed, 11 Nov 2026 06:21:43 +0000 Subject: [PATCH 1/2] ci: run the native shapes and unit tests on Python 3.14 The package supports Python 3.12 and later, but CI only exercised 3.12, so behaviour that differs on newer interpreters went unnoticed. A parallel job now builds the extension on Python 3.14 and runs the shape surface check and the unit tests whenever native or Python code changes, and the Verify aggregate requires it. --- .github/workflows/verify.yml | 52 +++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index e88e9ce2..dd0beb7b 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -20,6 +20,7 @@ jobs: e2e: ${{ steps.scope.outputs.e2e }} browser: ${{ steps.scope.outputs.browser }} packaging: ${{ steps.scope.outputs.packaging }} + python: ${{ steps.scope.outputs.python }} steps: - uses: actions/checkout@v4 with: @@ -37,16 +38,18 @@ jobs: echo "e2e=$2" echo "browser=$3" echo "packaging=$4" + echo "python=$5" } >> "${GITHUB_OUTPUT}" } if [[ "${EVENT_NAME}" != "pull_request" ]]; then - write_scope true true true true + write_scope true true true true true exit 0 fi focused=true packaging=false + python=false browser=false changed=false while IFS= read -r -d '' path; do @@ -56,6 +59,11 @@ jobs: packaging=true ;; esac + case "${path}" in + Cargo.*|crates/*|pyproject.toml|uv.lock|src/*|tests/unit/*|scripts/*|.github/workflows/verify.yml) + python=true + ;; + esac case "${path}" in ui/*) browser=true @@ -74,11 +82,11 @@ jobs: done < <(git diff --name-only -z "${BASE_SHA}" "${HEAD_SHA}") if [[ "${changed}" != "true" || "${focused}" != "true" ]]; then - write_scope true true true "${packaging}" + write_scope true true true "${packaging}" "${python}" exit 0 fi - write_scope false false "${browser}" "${packaging}" + write_scope false false "${browser}" "${packaging}" "${python}" checks: name: Static, UI, and unit checks @@ -112,6 +120,37 @@ jobs: - name: Run unit tests run: make test + python-latest: + name: Native shapes on Python 3.14 + needs: changes + if: needs.changes.outputs.python == 'true' + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + UV_PYTHON: "3.14" + MATURIN_PEP517_ARGS: --profile dev + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + version: "0.12.3" + enable-cache: true + cache-dependency-glob: uv.lock + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + - uses: Swatinem/rust-cache@v2 + - name: Install Python + run: uv python install "${UV_PYTHON}" + - name: Install dependencies + run: uv sync --locked --all-groups + - name: Confirm the interpreter version + run: uv run python -c 'import sys; assert sys.version_info[:2] == (3, 14), sys.version' + - name: Check the native shape surface + run: make check-shape-surface + - name: Run unit tests + run: uv run pytest tests/unit -q -n auto + integration: name: ClickHouse integration tests needs: changes @@ -233,13 +272,14 @@ jobs: verify: name: Verify if: always() - needs: [changes, checks, integration, e2e, browser, distributions, website] + needs: [changes, checks, python-latest, integration, e2e, browser, distributions, website] runs-on: ubuntu-latest steps: - name: Confirm all required verification jobs passed env: CHANGES_RESULT: ${{ needs.changes.result }} CHECKS_RESULT: ${{ needs.checks.result }} + PYTHON_LATEST_RESULT: ${{ needs.python-latest.result }} INTEGRATION_RESULT: ${{ needs.integration.result }} E2E_RESULT: ${{ needs.e2e.result }} BROWSER_RESULT: ${{ needs.browser.result }} @@ -250,8 +290,8 @@ jobs: echo "Required classification, static or website checks did not pass" >&2 exit 1 fi - for result in "${INTEGRATION_RESULT}" "${E2E_RESULT}" "${BROWSER_RESULT}" \ - "${DISTRIBUTIONS_RESULT}"; do + for result in "${PYTHON_LATEST_RESULT}" "${INTEGRATION_RESULT}" "${E2E_RESULT}" \ + "${BROWSER_RESULT}" "${DISTRIBUTIONS_RESULT}"; do if [[ "${result}" != "success" && "${result}" != "skipped" ]]; then echo "A selected verification suite did not pass: ${result}" >&2 exit 1 From 5ec93e67b0f6e98cd78b3bc242260510d1a4a303 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Wed, 11 Nov 2026 07:56:10 +0000 Subject: [PATCH 2/2] ci: run the Python 3.14 shape check nightly The job takes about eight runner minutes, so it moves out of the required Verify workflow into its own workflow that runs nightly, on manual dispatch and on pull requests that change it. --- .github/workflows/python-latest.yml | 46 +++++++++++++++++++++++++ .github/workflows/verify.yml | 52 ++++------------------------- 2 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/python-latest.yml diff --git a/.github/workflows/python-latest.yml b/.github/workflows/python-latest.yml new file mode 100644 index 00000000..ba87e9f6 --- /dev/null +++ b/.github/workflows/python-latest.yml @@ -0,0 +1,46 @@ +name: Python Latest + +on: + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + pull_request: + paths: + - .github/workflows/python-latest.yml + +permissions: + contents: read + +concurrency: + group: python-latest-${{ github.ref }} + cancel-in-progress: true + +jobs: + native-shapes: + name: Native shapes on Python 3.14 + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + UV_PYTHON: "3.14" + MATURIN_PEP517_ARGS: --profile dev + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + version: "0.12.3" + enable-cache: true + cache-dependency-glob: uv.lock + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + - uses: Swatinem/rust-cache@v2 + - name: Install Python + run: uv python install "${UV_PYTHON}" + - name: Install dependencies + run: uv sync --locked --all-groups + - name: Confirm the interpreter version + run: uv run python -c 'import sys; assert sys.version_info[:2] == (3, 14), sys.version' + - name: Check the native shape surface + run: make check-shape-surface + - name: Run unit tests + run: uv run pytest tests/unit -q -n auto diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index dd0beb7b..e88e9ce2 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -20,7 +20,6 @@ jobs: e2e: ${{ steps.scope.outputs.e2e }} browser: ${{ steps.scope.outputs.browser }} packaging: ${{ steps.scope.outputs.packaging }} - python: ${{ steps.scope.outputs.python }} steps: - uses: actions/checkout@v4 with: @@ -38,18 +37,16 @@ jobs: echo "e2e=$2" echo "browser=$3" echo "packaging=$4" - echo "python=$5" } >> "${GITHUB_OUTPUT}" } if [[ "${EVENT_NAME}" != "pull_request" ]]; then - write_scope true true true true true + write_scope true true true true exit 0 fi focused=true packaging=false - python=false browser=false changed=false while IFS= read -r -d '' path; do @@ -59,11 +56,6 @@ jobs: packaging=true ;; esac - case "${path}" in - Cargo.*|crates/*|pyproject.toml|uv.lock|src/*|tests/unit/*|scripts/*|.github/workflows/verify.yml) - python=true - ;; - esac case "${path}" in ui/*) browser=true @@ -82,11 +74,11 @@ jobs: done < <(git diff --name-only -z "${BASE_SHA}" "${HEAD_SHA}") if [[ "${changed}" != "true" || "${focused}" != "true" ]]; then - write_scope true true true "${packaging}" "${python}" + write_scope true true true "${packaging}" exit 0 fi - write_scope false false "${browser}" "${packaging}" "${python}" + write_scope false false "${browser}" "${packaging}" checks: name: Static, UI, and unit checks @@ -120,37 +112,6 @@ jobs: - name: Run unit tests run: make test - python-latest: - name: Native shapes on Python 3.14 - needs: changes - if: needs.changes.outputs.python == 'true' - runs-on: ubuntu-latest - timeout-minutes: 20 - env: - UV_PYTHON: "3.14" - MATURIN_PEP517_ARGS: --profile dev - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v5 - with: - version: "0.12.3" - enable-cache: true - cache-dependency-glob: uv.lock - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - - uses: Swatinem/rust-cache@v2 - - name: Install Python - run: uv python install "${UV_PYTHON}" - - name: Install dependencies - run: uv sync --locked --all-groups - - name: Confirm the interpreter version - run: uv run python -c 'import sys; assert sys.version_info[:2] == (3, 14), sys.version' - - name: Check the native shape surface - run: make check-shape-surface - - name: Run unit tests - run: uv run pytest tests/unit -q -n auto - integration: name: ClickHouse integration tests needs: changes @@ -272,14 +233,13 @@ jobs: verify: name: Verify if: always() - needs: [changes, checks, python-latest, integration, e2e, browser, distributions, website] + needs: [changes, checks, integration, e2e, browser, distributions, website] runs-on: ubuntu-latest steps: - name: Confirm all required verification jobs passed env: CHANGES_RESULT: ${{ needs.changes.result }} CHECKS_RESULT: ${{ needs.checks.result }} - PYTHON_LATEST_RESULT: ${{ needs.python-latest.result }} INTEGRATION_RESULT: ${{ needs.integration.result }} E2E_RESULT: ${{ needs.e2e.result }} BROWSER_RESULT: ${{ needs.browser.result }} @@ -290,8 +250,8 @@ jobs: echo "Required classification, static or website checks did not pass" >&2 exit 1 fi - for result in "${PYTHON_LATEST_RESULT}" "${INTEGRATION_RESULT}" "${E2E_RESULT}" \ - "${BROWSER_RESULT}" "${DISTRIBUTIONS_RESULT}"; do + for result in "${INTEGRATION_RESULT}" "${E2E_RESULT}" "${BROWSER_RESULT}" \ + "${DISTRIBUTIONS_RESULT}"; do if [[ "${result}" != "success" && "${result}" != "skipped" ]]; then echo "A selected verification suite did not pass: ${result}" >&2 exit 1