From 123aadd034d3bd90454849c32b79bc7ab027e69c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 07:30:15 +0000 Subject: [PATCH 1/6] pandas: Add versions 3.0.5, 3.0.6 Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- docs/packages/pandas.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/packages/pandas.yaml b/docs/packages/pandas.yaml index 1afe25e4f1..70159bc6c9 100644 --- a/docs/packages/pandas.yaml +++ b/docs/packages/pandas.yaml @@ -169,3 +169,5 @@ versions: - filename: pandas-2.2.2+0.gd9cdd2ee5a.dirty-cp39-cp39-manylinux_2_35_riscv64.whl sha256: 6daa75cf3dc9328c2cc033c4e78cbaaebd933e26985d9f5f26a2709422e000d0 requires-python: '>=3.9' +- version: 3.0.5 +- version: 3.0.6 From 32776f753ecce9ed2991052012d8ed453f243a4f Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sat, 19 Sep 2026 09:31:09 +0000 Subject: [PATCH 2/6] pandas: Add build-pandas.yml GitHub Actions workflow pandas was never ported from the old GitLab-based wheel_builder to the GitHub Actions system, so this branch's nightly version bump (3.0.5, 3.0.6) had no CI. Add build-pandas.yml, following the numpy/scipy build-from-checkout shape: cp311/cp312/cp313/cp314 (no cp314t, pandas declares no cpython-freethreading support), and carry forward the riscv64 NaN-test patch used for 3.0.0-3.0.3, re-verified to apply cleanly to v3.0.5 and v3.0.6. pandas's own pyproject.toml already covers the old GitLab config's license-file copy and default test command, so neither is carried forward; only LDFLAGS=-Wl,--strip-all needs restating since CIBW_ENVIRONMENT replaces its [tool.cibuildwheel] table wholesale. --- .github/workflows/build-pandas.yml | 108 ++++++++++++++++++ .../0001-disable-nan-test-on-riscv64.patch | 48 ++++++++ .../0001-disable-nan-test-on-riscv64.patch | 48 ++++++++ 3 files changed, 204 insertions(+) create mode 100644 .github/workflows/build-pandas.yml create mode 100644 patches/pandas/3.0.5/0001-disable-nan-test-on-riscv64.patch create mode 100644 patches/pandas/3.0.6/0001-disable-nan-test-on-riscv64.patch diff --git a/.github/workflows/build-pandas.yml b/.github/workflows/build-pandas.yml new file mode 100644 index 0000000000..fb001e76ee --- /dev/null +++ b/.github/workflows/build-pandas.yml @@ -0,0 +1,108 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +name: Build pandas wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/pandas.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-pandas.yml' + - 'docs/packages/pandas.yaml' + - 'patches/pandas/**' + push: + branches: [main] + paths: + - '.github/workflows/build-pandas.yml' + - 'docs/packages/pandas.yaml' + - 'patches/pandas/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: pandas + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build pandas ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 720 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + python: ["cp311", "cp312", "cp313", "cp314"] + + env: + PANDAS_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout pandas v${{ env.PANDAS_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: pandas-dev/pandas + ref: v${{ env.PANDAS_VERSION }} + submodules: true + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch pandas source + run: git apply python-wheels/patches/pandas/${{ env.PANDAS_VERSION }}/00*.patch + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + # CIBW_ENVIRONMENT replaces pandas's [tool.cibuildwheel] environment + # table wholesale, so its own LDFLAGS has to be restated here. + CIBW_ENVIRONMENT: >- + LDFLAGS=-Wl,--strip-all + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + PIP_ONLY_BINARY=numpy,hypothesis + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pandas-${{ env.PANDAS_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: ./wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish pandas ${{ matrix.version }} + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + with: + artifact-pattern: pandas-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/patches/pandas/3.0.5/0001-disable-nan-test-on-riscv64.patch b/patches/pandas/3.0.5/0001-disable-nan-test-on-riscv64.patch new file mode 100644 index 0000000000..469859f1d7 --- /dev/null +++ b/patches/pandas/3.0.5/0001-disable-nan-test-on-riscv64.patch @@ -0,0 +1,48 @@ +From 5e254d628784dd803ff9b492b06db8118b4bbaee Mon Sep 17 00:00:00 2001 +From: Julien Stephan +Date: Thu, 26 Mar 2026 13:41:01 +0100 +Subject: [PATCH] disable nan test on riscv64 + +Upstream-Status: To upstream [To send when we will add riscv64 support upstream] +Signed-off-by: Julien Stephan +--- + pandas/tests/tools/test_to_datetime.py | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py +index 466bc5b860..3e5f28c5d1 100644 +--- a/pandas/tests/tools/test_to_datetime.py ++++ b/pandas/tests/tools/test_to_datetime.py +@@ -10,6 +10,7 @@ from datetime import ( + ) + from decimal import Decimal + import locale ++import platform + import zoneinfo + + from dateutil.parser import parse +@@ -1795,6 +1796,10 @@ class TestToDatetimeUnit: + tm.assert_index_equal(result, expected) + + # with a nan! ++ # skip test on riscv64 ++ if platform.machine() == 'riscv64': ++ return ++ + result = to_datetime(np.array([item, np.nan]), unit=unit, cache=cache) + assert result.isna()[1] + tm.assert_index_equal(result[:1], expected.astype("M8[s]")) +@@ -3830,6 +3835,10 @@ def test_to_datetime_lxml_elementunicoderesult_with_format(cache): + + + def test_to_datetime_missing_component_no_runtime_warning(): ++ # skip test on riscv64 ++ if platform.machine() == 'riscv64': ++ return ++ + df = DataFrame( + { + "year": [2023, 2023], +-- +2.54.0 + diff --git a/patches/pandas/3.0.6/0001-disable-nan-test-on-riscv64.patch b/patches/pandas/3.0.6/0001-disable-nan-test-on-riscv64.patch new file mode 100644 index 0000000000..469859f1d7 --- /dev/null +++ b/patches/pandas/3.0.6/0001-disable-nan-test-on-riscv64.patch @@ -0,0 +1,48 @@ +From 5e254d628784dd803ff9b492b06db8118b4bbaee Mon Sep 17 00:00:00 2001 +From: Julien Stephan +Date: Thu, 26 Mar 2026 13:41:01 +0100 +Subject: [PATCH] disable nan test on riscv64 + +Upstream-Status: To upstream [To send when we will add riscv64 support upstream] +Signed-off-by: Julien Stephan +--- + pandas/tests/tools/test_to_datetime.py | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py +index 466bc5b860..3e5f28c5d1 100644 +--- a/pandas/tests/tools/test_to_datetime.py ++++ b/pandas/tests/tools/test_to_datetime.py +@@ -10,6 +10,7 @@ from datetime import ( + ) + from decimal import Decimal + import locale ++import platform + import zoneinfo + + from dateutil.parser import parse +@@ -1795,6 +1796,10 @@ class TestToDatetimeUnit: + tm.assert_index_equal(result, expected) + + # with a nan! ++ # skip test on riscv64 ++ if platform.machine() == 'riscv64': ++ return ++ + result = to_datetime(np.array([item, np.nan]), unit=unit, cache=cache) + assert result.isna()[1] + tm.assert_index_equal(result[:1], expected.astype("M8[s]")) +@@ -3830,6 +3835,10 @@ def test_to_datetime_lxml_elementunicoderesult_with_format(cache): + + + def test_to_datetime_missing_component_no_runtime_warning(): ++ # skip test on riscv64 ++ if platform.machine() == 'riscv64': ++ return ++ + df = DataFrame( + { + "year": [2023, 2023], +-- +2.54.0 + From e05a1ed9bb170231194ca82ccfc0b11c6b154a62 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 20 Sep 2026 07:17:23 +0000 Subject: [PATCH 3/6] pandas: commit patch and re-tag to fix versioneer dirty version Building pandas 3.0.5/3.0.6 leaves the checkout dirty relative to its tag after applying the riscv64 nan-test patch. pandas uses versioneer, which renders the version from `git describe --tags --dirty` with no setuptools_scm-style pretend-version override, so the build produced 3.0.6+0.g2905718.dirty instead of the clean 3.0.6, and the publish dry-run rejected it. Commit the patch and force the tag onto the new commit so describe reports zero distance and a clean tree again, same pattern as build-swiglpk.yml. --- .github/workflows/build-pandas.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-pandas.yml b/.github/workflows/build-pandas.yml index fb001e76ee..25ac13d639 100644 --- a/.github/workflows/build-pandas.yml +++ b/.github/workflows/build-pandas.yml @@ -71,7 +71,14 @@ jobs: persist-credentials: false - name: Patch pandas source - run: git apply python-wheels/patches/pandas/${{ env.PANDAS_VERSION }}/00*.patch + # pandas uses versioneer (git describe --tags --dirty), which has no + # SETUPTOOLS_SCM_PRETEND_VERSION-style override (gotcha 315). Commit the + # patch and re-point the tag at it so describe reports the exact tagged + # version again, same as build-swiglpk.yml. + run: | + git apply python-wheels/patches/pandas/${{ env.PANDAS_VERSION }}/00*.patch + git -c user.name=ci -c user.email=ci@localhost commit -am "riscv64 patches" + git tag -f v${{ env.PANDAS_VERSION }} - name: Build wheels uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 From 9ca3b4a7419b0764bc5cdb73ff3af4c6812596b7 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 20 Sep 2026 15:55:43 +0000 Subject: [PATCH 4/6] pandas: fix versioneer dirty version surviving into cibuildwheel container The host-side patch/commit/retag step (e05a1ed9b) already produces a clean git describe at the point it runs, but pandas's own before-build hook (scripts/cibw_before_build.sh, wired via [tool.cibuildwheel] before-build) runs inside the cibuildwheel container afterwards and appends LICENSES/* into the tracked LICENSE file, re-dirtying the tree right before meson resolves the version via versioneer. Override CIBW_BEFORE_BUILD to re-run that hook and then commit + re-tag again inside the same container, before the build reads the version. Verified by replicating the exact sequence against a shallow clone of the v3.0.5 tag: generate_version.py --print reports a clean "3.0.5" after the host-side fix alone, but reverts to "3.0.5+0.g.dirty" once the before-build hook runs, and is clean again once it's followed by the same commit+retag. Also adds gotcha 381 documenting the general shape of this trap. --- .github/workflows/build-pandas.yml | 11 +++++ .../references/gotchas-index.md | 6 ++- .../gotchas/sdist-source-and-versioning.md | 42 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-pandas.yml b/.github/workflows/build-pandas.yml index 25ac13d639..707a29fd01 100644 --- a/.github/workflows/build-pandas.yml +++ b/.github/workflows/build-pandas.yml @@ -92,6 +92,17 @@ jobs: LDFLAGS=-Wl,--strip-all PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ PIP_ONLY_BINARY=numpy,hypothesis + # cibuildwheel copies the source into a fresh container per build, and + # pandas's own before-build (scripts/cibw_before_build.sh) appends + # LICENSES/* into LICENSE there, re-dirtying the tree that versioneer's + # git describe reads when the meson build resolves the version (gotcha + # 315). CIBW_BEFORE_BUILD replaces pandas's [tool.cibuildwheel] + # before-build wholesale, so re-run it here, then commit and re-tag in + # the same container before the build reads the version. + CIBW_BEFORE_BUILD: >- + PACKAGE_DIR={package} bash {package}/scripts/cibw_before_build.sh && + git -C {package} -c user.name=ci -c user.email=ci@localhost commit -am "cibw before-build" && + git -C {package} tag -f v${{ env.PANDAS_VERSION }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: diff --git a/skills/python-project-porting/references/gotchas-index.md b/skills/python-project-porting/references/gotchas-index.md index 3da4263fce..d7979950e8 100644 --- a/skills/python-project-porting/references/gotchas-index.md +++ b/skills/python-project-porting/references/gotchas-index.md @@ -1,6 +1,6 @@ # Gotchas index — router for the themed gotcha files -The porting gotchas (370 of them) live in [`references/gotchas/`](gotchas/), split by theme so only the relevant slice loads. Every gotcha keeps a **permanent number** cited elsewhere as "gotcha N" (and in workflow comments as "CLAUDE.md gotcha N"). Numbers are stable IDs — **not sequential**, and four are **reused** with different content (two each of 33, 55, 56, 57), disambiguated by theme below. +The porting gotchas (371 of them) live in [`references/gotchas/`](gotchas/), split by theme so only the relevant slice loads. Every gotcha keeps a **permanent number** cited elsewhere as "gotcha N" (and in workflow comments as "CLAUDE.md gotcha N"). Numbers are stable IDs — **not sequential**, and four are **reused** with different content (two each of 33, 55, 56, 57), disambiguated by theme below. ## How to find the gotcha you need @@ -126,6 +126,10 @@ The porting gotchas (370 of them) live in [`references/gotchas/`](gotchas/), spl wrong commit — check `git merge-base --is-ancestor origin/main` before trusting it. - **352** — A gitlink with no `.gitmodules` entry breaks `actions/checkout`'s own persist-credentials cleanup, not the checkout itself. +- **381** — A gotcha 315-style commit+retag fix for a `versioneer` dirty tree can still + read dirty inside the cibuildwheel container if the project's own `before-build` hook + modifies a tracked file after the retag — override `CIBW_BEFORE_BUILD` to redo the + commit+retag after it. ### cibuildwheel mechanics, the matrix & abi3 — [`gotchas/cibuildwheel-matrix-and-abi3.md`](gotchas/cibuildwheel-matrix-and-abi3.md) diff --git a/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md b/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md index e3b35e7bff..7f37b7d067 100644 --- a/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md +++ b/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md @@ -589,3 +589,45 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/sdist-source-and-versi the submodule-cleanup routine in the first place — no patch to the upstream tree needed, and `persist-credentials: false`'s only purpose (not leaking the checkout token into the built artifact) is moot for plain, unauthenticated `git clone`/`fetch`. + +381. **A host-side `git apply` -> commit -> `git tag -f` fix for a `versioneer` dirty tree + (gotcha 315's mechanism) can still leave the tree dirty *inside* the cibuildwheel + container if the project's own `before-build` hook also modifies a tracked file (the + pandas case).** `build-pandas.yml`'s "Patch pandas source" step applies the riscv64 + patch, commits it under the throwaway `ci` identity and re-tags `v` at + `HEAD` -- verified empirically (shallow clone, replicate the three commands, then run + `generate_version.py --print`, the exact script pandas's `meson.build` invokes at + configure time) that this alone *does* produce a clean, zero-distance version, matching + gotcha 315's `git tag -f`-based fix. But pandas's own `[tool.cibuildwheel] before-build` + (`scripts/cibw_before_build.sh`) -- which our `CIBW_ENVIRONMENT` override doesn't touch, + since that's a separate cibuildwheel option -- runs *inside* the container, after + cibuildwheel tars the whole `git describe`-clean working directory in (including + `.git`, confirmed by reading `oci_container.py`'s `copy_into`: a plain `tar -c -f - .` + with no `.git` exclusion), and appends `LICENSES/*` into the tracked `LICENSE` file -- + re-dirtying the tree at the exact point (`pandas/meson.build`'s top-level + `run_command(['generate_version.py', '--print'])`, which falls back to + `versioneer.get_version()` before `_version_meson.py` exists) where the version is + actually resolved. Reproduced exactly: running `cibw_before_build.sh` against the + already-clean, already-retagged checkout turns `generate_version.py --print`'s output + from `3.0.5` back into `3.0.5+0.g.dirty` -- the same shape CI reported. Each + matrix leg (cp311/cp312/cp313/cp314) shows a *different* hash for the *same* pandas + version for an unrelated, harmless reason: each is an independent container getting its + own host-side commit (from its own job's "Patch pandas source" step) plus its own + container-side commit; only the *dirty* suffix was the actual bug. + - **Fix: override `CIBW_BEFORE_BUILD` to re-run the project's own before-build command + and then commit + re-tag again, inside the same container, right before the build + reads the version** -- not by deleting or working around the upstream hook (goal 2: + mirror upstream's own CI), and not by moving the host-side patch/commit/retag step, + since that step's output is still correct at the point it runs and gets faithfully + copied into the container. `CIBW_BEFORE_BUILD` replaces `[tool.cibuildwheel] + before-build` wholesale (same env-var-over-pyproject.toml precedence as + `CIBW_ENVIRONMENT`), so the override must restate pandas's own command + (`PACKAGE_DIR={package} bash {package}/scripts/cibw_before_build.sh`) before chaining + `git -C {package} commit -am ... && git -C {package} tag -f v` after it. + - **General shape of the trap**: gotcha 315's fix only guarantees a clean tree at the + moment the fix step runs. Any later hook that runs in a *different* environment + copy (a fresh container, a fresh clone) and touches a tracked file reopens the same + dirty-tree problem, even though nothing about the original fix was wrong. Before + trusting a commit+retag fix, trace every step between it and whatever actually + triggers the version-detection call (here, `pip wheel` -> meson configure), not just + the steps visible in the GitHub Actions log. From e5fa6c67ea994e3f9b643cba86cdd5aafa6dde32 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 20 Sep 2026 15:57:51 +0000 Subject: [PATCH 5/6] gotchas: renumber the new versioneer-in-container entry to 382 This branch forked from main before gotcha 381 (the nightly-upgrade force-push-wipe trap, documented in pr-ci-and-maintainer.md) existed there, so the previous commit's own gotcha 381 was picked independently and collides with it. Renumber to 382, the next free number on main. --- skills/python-project-porting/references/gotchas-index.md | 2 +- .../references/gotchas/sdist-source-and-versioning.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/python-project-porting/references/gotchas-index.md b/skills/python-project-porting/references/gotchas-index.md index d7979950e8..726c220962 100644 --- a/skills/python-project-porting/references/gotchas-index.md +++ b/skills/python-project-porting/references/gotchas-index.md @@ -126,7 +126,7 @@ The porting gotchas (371 of them) live in [`references/gotchas/`](gotchas/), spl wrong commit — check `git merge-base --is-ancestor origin/main` before trusting it. - **352** — A gitlink with no `.gitmodules` entry breaks `actions/checkout`'s own persist-credentials cleanup, not the checkout itself. -- **381** — A gotcha 315-style commit+retag fix for a `versioneer` dirty tree can still +- **382** — A gotcha 315-style commit+retag fix for a `versioneer` dirty tree can still read dirty inside the cibuildwheel container if the project's own `before-build` hook modifies a tracked file after the retag — override `CIBW_BEFORE_BUILD` to redo the commit+retag after it. diff --git a/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md b/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md index 7f37b7d067..65fc8da1fa 100644 --- a/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md +++ b/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md @@ -590,7 +590,7 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/sdist-source-and-versi needed, and `persist-credentials: false`'s only purpose (not leaking the checkout token into the built artifact) is moot for plain, unauthenticated `git clone`/`fetch`. -381. **A host-side `git apply` -> commit -> `git tag -f` fix for a `versioneer` dirty tree +382. **A host-side `git apply` -> commit -> `git tag -f` fix for a `versioneer` dirty tree (gotcha 315's mechanism) can still leave the tree dirty *inside* the cibuildwheel container if the project's own `before-build` hook also modifies a tracked file (the pandas case).** `build-pandas.yml`'s "Patch pandas source" step applies the riscv64 From 0a6dc68bed338e1638cdcb66880c0b4095de51cd Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Mon, 21 Sep 2026 07:30:29 +0000 Subject: [PATCH 6/6] Remove skills/ changes from this PR This PR should only touch the pandas port itself; the gotcha 454 entry added here has since collided with a different gotcha 454 recorded on main and doesn't belong in a port-scoped PR. --- .../references/gotchas-index.md | 6 +-- .../gotchas/sdist-source-and-versioning.md | 42 ------------------- 2 files changed, 1 insertion(+), 47 deletions(-) diff --git a/skills/python-project-porting/references/gotchas-index.md b/skills/python-project-porting/references/gotchas-index.md index 7ca05a7be2..0e03f3f3c1 100644 --- a/skills/python-project-porting/references/gotchas-index.md +++ b/skills/python-project-porting/references/gotchas-index.md @@ -1,6 +1,6 @@ # Gotchas index — router for the themed gotcha files -The porting gotchas (434 of them) live in [`references/gotchas/`](gotchas/), split by theme so only the relevant slice loads. Every gotcha keeps a **permanent number** cited elsewhere as "gotcha N" (and in workflow comments as "CLAUDE.md gotcha N"). Numbers are stable IDs — **not sequential**, and four are **reused** with different content (two each of 33, 55, 56, 57), disambiguated by theme below. +The porting gotchas (433 of them) live in [`references/gotchas/`](gotchas/), split by theme so only the relevant slice loads. Every gotcha keeps a **permanent number** cited elsewhere as "gotcha N" (and in workflow comments as "CLAUDE.md gotcha N"). Numbers are stable IDs — **not sequential**, and four are **reused** with different content (two each of 33, 55, 56, 57), disambiguated by theme below. ## How to find the gotcha you need @@ -248,10 +248,6 @@ The porting gotchas (434 of them) live in [`references/gotchas/`](gotchas/), spl - **406** — Gotcha 103's byte-for-byte sdist proof cannot come out clean when upstream cuts releases from a non-public tree: a `[tool.cibuildwheel]`-only difference is not a wrong pin, and the released sdist's `test-command` can name a script that never existed (the nvtx case). -- **454** — A gotcha 315-style commit+retag fix for a `versioneer` dirty tree can still - read dirty inside the cibuildwheel container if the project's own `before-build` hook - modifies a tracked file after the retag — override `CIBW_BEFORE_BUILD` to redo the - commit+retag after it. ### cibuildwheel mechanics, the matrix & abi3 — [`gotchas/cibuildwheel-matrix-and-abi3.md`](gotchas/cibuildwheel-matrix-and-abi3.md) diff --git a/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md b/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md index 82af0d831b..813ed9b9c2 100644 --- a/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md +++ b/skills/python-project-porting/references/gotchas/sdist-source-and-versioning.md @@ -619,45 +619,3 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/sdist-source-and-versi - Together those two make build-from-checkout the right shape for a monorepo-subdirectory package like this, not sdist→bdist: the checkout supplies the headers the `setup.py` reaches for *and* the test helpers the sdist drops. - -454. **A host-side `git apply` -> commit -> `git tag -f` fix for a `versioneer` dirty tree - (gotcha 315's mechanism) can still leave the tree dirty *inside* the cibuildwheel - container if the project's own `before-build` hook also modifies a tracked file (the - pandas case).** `build-pandas.yml`'s "Patch pandas source" step applies the riscv64 - patch, commits it under the throwaway `ci` identity and re-tags `v` at - `HEAD` -- verified empirically (shallow clone, replicate the three commands, then run - `generate_version.py --print`, the exact script pandas's `meson.build` invokes at - configure time) that this alone *does* produce a clean, zero-distance version, matching - gotcha 315's `git tag -f`-based fix. But pandas's own `[tool.cibuildwheel] before-build` - (`scripts/cibw_before_build.sh`) -- which our `CIBW_ENVIRONMENT` override doesn't touch, - since that's a separate cibuildwheel option -- runs *inside* the container, after - cibuildwheel tars the whole `git describe`-clean working directory in (including - `.git`, confirmed by reading `oci_container.py`'s `copy_into`: a plain `tar -c -f - .` - with no `.git` exclusion), and appends `LICENSES/*` into the tracked `LICENSE` file -- - re-dirtying the tree at the exact point (`pandas/meson.build`'s top-level - `run_command(['generate_version.py', '--print'])`, which falls back to - `versioneer.get_version()` before `_version_meson.py` exists) where the version is - actually resolved. Reproduced exactly: running `cibw_before_build.sh` against the - already-clean, already-retagged checkout turns `generate_version.py --print`'s output - from `3.0.5` back into `3.0.5+0.g.dirty` -- the same shape CI reported. Each - matrix leg (cp311/cp312/cp313/cp314) shows a *different* hash for the *same* pandas - version for an unrelated, harmless reason: each is an independent container getting its - own host-side commit (from its own job's "Patch pandas source" step) plus its own - container-side commit; only the *dirty* suffix was the actual bug. - - **Fix: override `CIBW_BEFORE_BUILD` to re-run the project's own before-build command - and then commit + re-tag again, inside the same container, right before the build - reads the version** -- not by deleting or working around the upstream hook (goal 2: - mirror upstream's own CI), and not by moving the host-side patch/commit/retag step, - since that step's output is still correct at the point it runs and gets faithfully - copied into the container. `CIBW_BEFORE_BUILD` replaces `[tool.cibuildwheel] - before-build` wholesale (same env-var-over-pyproject.toml precedence as - `CIBW_ENVIRONMENT`), so the override must restate pandas's own command - (`PACKAGE_DIR={package} bash {package}/scripts/cibw_before_build.sh`) before chaining - `git -C {package} commit -am ... && git -C {package} tag -f v` after it. - - **General shape of the trap**: gotcha 315's fix only guarantees a clean tree at the - moment the fix step runs. Any later hook that runs in a *different* environment - copy (a fresh container, a fresh clone) and touches a tracked file reopens the same - dirty-tree problem, even though nothing about the original fix was wrong. Before - trusting a commit+retag fix, trace every step between it and whatever actually - triggers the version-detection call (here, `pip wheel` -> meson configure), not just - the steps visible in the GitHub Actions log.