Skip to content

Add Python 2.7 wheel builds for Windows platforms#378

Merged
etrepum merged 9 commits into
mainfrom
claude/fix-simplejson-377-WHpB1
Apr 24, 2026
Merged

Add Python 2.7 wheel builds for Windows platforms#378
etrepum merged 9 commits into
mainfrom
claude/fix-simplejson-377-WHpB1

Conversation

@etrepum

@etrepum etrepum commented Apr 24, 2026

Copy link
Copy Markdown
Member

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_py27 job):

    • Converted from a single-platform job to a matrix-based job supporting multiple OS/architecture combinations
    • Added Windows builds for both AMD64 and x86 architectures alongside the existing Ubuntu x86_64 build
    • Updated CIBW_ARCHS_LINUX to the more generic CIBW_ARCHS to support architecture specification across platforms
    • Modified artifact naming to include OS and architecture information for clarity
  • Dependency updates:

    • Updated gate_windows job to depend on both build_wheels and build_wheels_py27 to ensure Windows wheel builds complete successfully

Rationale

This change addresses an issue where offline/--no-index installations 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 missing setuptools>=42 in 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

claude added 9 commits April 24, 2026 15:42
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
@etrepum etrepum enabled auto-merge April 24, 2026 17:49
@etrepum etrepum added this pull request to the merge queue Apr 24, 2026
Merged via the queue into main with commit 639b2ee Apr 24, 2026
26 checks passed
@etrepum etrepum deleted the claude/fix-simplejson-377-WHpB1 branch April 24, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error: No matching distribution found for setuptools>=42 from version 4.0.0 and above on python 2.7

2 participants