Add Python 2.7 wheel builds for Windows platforms#378
Merged
Conversation
Fixes #377. Pre-4.0 simplejson installed cleanly from PyPI on offline Python 2.7 builds via a wheelhouse populated with `pip download`. 4.0+ ships a `py3-none-any.whl` alongside the sdist, so Python 2.7 wheelhouses contain only the sdist for the pure-Python path. Modern pip then runs a PEP 517 isolated build on that sdist and requires setuptools>=42 from the wheelhouse, which offline users usually do not seed. Add `--universal` to the `bdist_wheel` step in the build_sdist job so the wheel is tagged `py2.py3-none-any` and is usable on both interpreters. The sdist install path and the separate C-extension wheels produced by cibuildwheel are unchanged, and pyproject.toml / the test_pep517_build job stay in place for modern ecosystem tooling. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
Expands build_wheels_py27 into a matrix that covers both Linux x86_64 (unchanged) and Windows AMD64. Published cp27 wheels previously only covered manylinux1 / manylinux2010 x86_64, so Py2.7-on-Windows users had no matching binary wheel on PyPI, pip fell through to the sdist, and the PEP 517 isolated build failed under --no-index on wheelhouses without setuptools>=42. This was the scenario in #377. Ships alongside the universal py2.py3-none-any fallback wheel from the previous commit, which still catches platforms this matrix does not cover (macOS, aarch64 Linux, ppc64le, etc.). Matrix notes: - cibuildwheel v1 looks at the arch env var for the runner platform it actually runs on and ignores the others, so setting both CIBW_ARCHS_LINUX and CIBW_ARCHS_WINDOWS is safe. - Artifact names are now wheels-py27-<os>-<arch> so the Linux and Windows uploads don't collide under upload-artifact@v7's unique- name requirement. upload_pypi / upload_pypi_test use download-artifact@v8 with merge-multiple: true, so the rename is transparent to release uploads. - Adds build_wheels_py27 to gate_windows.needs so Windows branch protection catches Py2.7 Windows build failures. Per AGENTS.md, Py2 builds cannot be reproduced locally - if Windows cp27 fails under cibuildwheel v1.12.0 on windows-latest (VC++ 9.0 toolchain surface), fail-fast: false keeps the Linux wheel green while we iterate. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
Adds a third entry to the build_wheels_py27 matrix covering
windows-latest/x86, so 32-bit Py2.7 interpreters on Windows (still
common in legacy corporate installs, where the default Py2.7 MSI
was 32-bit for years) also get a pre-built wheel on PyPI. Switches
the arch env from the platform-specific CIBW_ARCHS_{LINUX,WINDOWS}
pair to the platform-agnostic CIBW_ARCHS, matching the pattern in
build_wheels.
Drops fail-fast: false - branch protection won't merge with a red
matrix entry anyway, so letting siblings cancel early on a failure
is the more useful default.
https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
Reverts the --universal flag added in 8fc52d0. Retagging the fallback pure-Python wheel to py2.py3-none-any would be picked up by pip on any Py2.7 platform without a matching cp27 binary wheel (macOS, aarch64/ppc64le Linux). Those users currently build from the sdist and get the C extension; under the universal wheel they would silently get the pure-Python implementation instead - a measurable perf regression with no user-visible signal. The cp27 Windows AMD64 + x86 wheels added in ae97829 and 61a04d5 cover the original #377 reporter (Py2.7 on Windows). Py2.7 users on macOS or non-x86_64 Linux fall back to the sdist as they did before, which is loud-failure behavior (online: builds fine, gets speedups; offline: clear error) rather than silent slowdown. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
v1.12.0 removed cp27 from WINDOWS_PYTHONS, so the Windows matrix entries added in ae97829 / 61a04d5 fail at identifier selection ("cibuildwheel: No build identifiers selected: BuildSelector('cp27-*' - 'pp*')") before the build phase even starts. v1.11.1 is the last release that still carries cp27 identifiers for both Linux (manylinux1 Docker image) and Windows (NuGet python2 package), so one version pin serves all three matrix entries (linux/x86_64, windows/AMD64, windows/x86). Also updates the AGENTS.md cibuildwheel gotchas note, which was pinning readers to the broken v1.12.0, so the next person touching this job learns the v1.11.1 reasoning from the doc rather than rediscovering it from CI. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
My earlier v1.11.1 pin (85aba3c) did not fix "No build identifiers selected" on Windows, which confirmed a reading of the cibuildwheel changelog: v1.11.0 did not *remove* cp27 from Windows, it gated it behind a custom-compiler flag. cibuildwheel/windows.py filters cp27 out of WINDOWS_PYTHONS during identifier selection unless both DISTUTILS_USE_SDK and MSSdk are present in the cibuildwheel process environment; Microsoft pulled the VC 9.0 ("Visual C++ Compiler for Python 2.7") download years ago, so cibuildwheel won't pretend it has a usable compiler by default. v2.0.0 is the release that dropped cp27 entirely, not v1.12. So the fix is not a version pin, it is environment: - Restore pypa/cibuildwheel@v1.12.0 (the latest v1 release). - Set DISTUTILS_USE_SDK=1 and MSSdk=1 at the step scope so cibuildwheel itself sees them during identifier selection, and mirror them via CIBW_ENVIRONMENT_WINDOWS so the per-wheel build subprocess forwards them to distutils. - Add an ilammy/msvc-dev-cmd@v1 activation step on Windows runners with arch matching the wheel (x64 for AMD64, x86 for x86), so distutils finds an MSVC toolchain via INCLUDE/LIB/PATH in place of the missing VC 9.0 installer. Also updates AGENTS.md to document the real gate (env vars, not version number) and adds a "do not chase a v1.11.x pin" warning so the next person looking at a "No build identifiers selected" failure reaches the right fix instead of the one I tried first. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
The DISTUTILS_USE_SDK / MSSdk / CIBW_ENVIRONMENT_WINDOWS triple added in e494f4f was set unconditionally across all three build_wheels_py27 matrix entries. That's functionally a no-op on the Linux cp27 entry (distutils on POSIX doesn't consult those vars, and cibuildwheel targeting Linux ignores CIBW_ENVIRONMENT_WINDOWS), but it reads like those env vars matter everywhere. Guard them with `runner.os == 'Windows'` so the Linux cp27 entry sees an empty env and the Windows- only intent is explicit at the call site. build_wheels (the modern Py3 job) is a separate job that doesn't touch any of this - its cibuildwheel@v3.4.1 step has no DISTUTILS_ USE_SDK / MSSdk / msvc-dev-cmd wiring and isn't affected. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
Bumps VERSION in setup.py, conf.py, and simplejson/__init__.py to 4.1.1 and stamps the CHANGES.txt entry with today's date. The 4.1.1 release closes #377: offline / --no-index installs on Py2.7-on- Windows were failing at the PEP 517 isolated-build step because no cp27 win_amd64 / win32 wheel existed on PyPI and the sdist fallback required setuptools>=42 in the wheelhouse. build_wheels_py27 now builds those wheels directly via cibuildwheel v1.12.0 plus the DISTUTILS_USE_SDK / MSSdk gate and ilammy/msvc-dev-cmd. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
Dedupe CI: feature-branch pushes with an open PR were firing both the push and pull_request events on the same SHA, doubling the workflow runs (and the cibuildwheel minute burn). Scoping push to branches: [main] + tags: [v*, test-v*] leaves pull_request as the single trigger for development branches, while preserving the existing release flow - upload_pypi / upload_pypi_test gate on startsWith(github.event.ref, 'refs/tags/v') / 'refs/tags/test-v', and those still fire under the new push config. merge_group keeps the merge-queue gate jobs triggerable. Also drops the commented-out release-trigger example that was sitting above the old on: line; if we ever want that, the git history has it. https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extend the Python 2.7 wheel building CI job to support Windows platforms (AMD64 and x86 architectures) in addition to the existing Linux x86_64 builds.
Changes
CI workflow updates (
build_wheels_py27job):CIBW_ARCHS_LINUXto the more genericCIBW_ARCHSto support architecture specification across platformsDependency updates:
gate_windowsjob to depend on bothbuild_wheelsandbuild_wheels_py27to ensure Windows wheel builds complete successfullyRationale
This change addresses an issue where offline/
--no-indexinstallations on Python 2.7 for Windows were failing because no matching binary wheels were available on PyPI. Previously, the build process would fall back to the source distribution, which would fail during the PEP 517 isolated-build step due to missingsetuptools>=42in the wheelhouse. By building wheels for Windows platforms, users can now perform offline installations without encountering these build failures.Fixes: #377
https://claude.ai/code/session_01Sc7XDDu56uaU1xZEjJR1GY