Skip to content

ci: build a pure-Python distribution instead of platform-specific binary wheels - #127

Open
Areustle wants to merge 5 commits into
mainfrom
ci-pure-python
Open

ci: build a pure-Python distribution instead of platform-specific binary wheels#127
Areustle wants to merge 5 commits into
mainfrom
ci-pure-python

Conversation

@Areustle

Copy link
Copy Markdown
Contributor

Problem

main is red. All 21 wheel jobs fail with:

Build failed because a pure Python wheel was generated.

Since the C++ zsteps extension was removed, nuspacesim is pure Python — but both PyPI workflows still drive cibuildwheel across a 7-version × 2-OS × 2-arch matrix. cibuildwheel treats a pure-Python result as an error, so every job fails by construction. A pure-Python project needs exactly one py3-none-any wheel.

What changed

CI/CD workflow (pypi-build-test.yml)

  • The wheel matrix becomes a real pytest matrix over the versions setup.cfg actually declares (3.9–3.13) on ubuntu + macos. Worth noting: the old workflow never ran the suite directly — it relied on cibuildwheel's test-command, and its CIBW_TEST_SKIP excluded macOS and every non-native arch. So macOS was effectively untested. Tests now run from a scratch directory against the installed package.
  • New build job (gated behind the tests) produces sdist + wheel, runs twine check, and asserts exactly one py3-none-any wheel — so if a binary dependency ever creeps back in, it fails loudly here instead of silently shipping a platform-specific artifact.

Publish workflow (pypi-build-test-publish.yml)

  • Build once, publish once. The publish job previously carried the same 21-way matrix as the build job, so a release would have attempted 21 uploads of the same file — only the first could succeed.
  • The sdist now ships alongside the wheel (previously wheels only).

Build config

  • Dropped [tool.cibuildwheel] from pyproject.toml and ext_package = nuspacesim from setup.cfg — both meaningless without ext_modules.

Checkouts use fetch-depth: 0 instead of the git fetch --unshallow dance so setuptools_scm sees tags; actions/checkout → v4, setup-python → v5.

Verification

Run locally, not just asserted in YAML:

  • python -m build → exactly one py3-none-any wheel + sdist
  • both pass twine check
  • wheel contains the packaged data (CONEX table, 13 cloud maps)
  • full suite (171 tests) passes against that wheel installed in a clean venv, run from a scratch directory
  • nuspacesim --version works from the installed console entry point

Notes for review

  • Python version matrix is now 3.9–3.13, matching python_requires and the classifiers. The old matrix listed 3.14 and 3.15, which the package doesn't declare support for. If you want 3.14+, add the classifier and the matrix entry together — happy to do that in a follow-up.
  • PyPI auth is unchanged (__token__ + PYPI_SECRET). Trusted Publishing (OIDC) would be the modern choice, but it needs configuration on the PyPI side, so I didn't change it unilaterally.
  • Not touched: the two conda-* workflows. They're dormant (workflow_dispatch-only, push/PR triggers commented out) and independently broken — they conda build ... recipe but no recipe/ directory exists. Separate pre-existing rot; worth its own cleanup or deletion.

🤖 Generated with Claude Code

Areustle and others added 5 commits August 17, 2026 15:44
nuspacesim has no compiled extensions since the C++ zsteps removal, but both
PyPI workflows still drove cibuildwheel across a 7-version x 2-OS x 2-arch
matrix. Every one of those 21 jobs now fails on main with "Build failed because
a pure Python wheel was generated" -- cibuildwheel treats a pure-Python result
as an error. A pure-Python project needs exactly one py3-none-any wheel.

CI/CD workflow:
- Replace the wheel matrix with a real pytest matrix over the Python versions
  setup.cfg actually declares (3.9-3.13), on ubuntu and macos. The old workflow
  never ran the suite directly; it relied on cibuildwheel's test-command, whose
  CIBW_TEST_SKIP excluded macOS and every non-native arch outright. Tests now
  run from a scratch directory against the installed package.
- Add a build job producing sdist + wheel, gated behind the tests, with
  `twine check` and an assertion that exactly one py3-none-any wheel is
  produced -- so a re-introduced binary dependency fails loudly here rather
  than silently shipping a platform-specific artifact.

Publish workflow:
- Build once, publish once. The publish job previously carried the same 21-way
  matrix as the build job, so a release would have attempted 21 uploads of the
  same file; only the first could succeed.
- Ship the sdist alongside the wheel (previously wheels only).

Also drop two leftovers from the extension era: the [tool.cibuildwheel] section
in pyproject.toml and `ext_package = nuspacesim` in setup.cfg, which is
meaningless without ext_modules.

Checkouts use fetch-depth: 0 rather than the fetch --unshallow dance, so
setuptools_scm sees tags; actions/checkout and setup-python moved to v4/v5.

Verified locally: `python -m build` produces one py3-none-any wheel plus an
sdist, both pass twine check, the wheel carries the CONEX table and cloud maps,
and the full suite (171 tests) passes against that wheel installed in a clean
venv, as does the nuspacesim console entry point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub runners now warn that Node 20 actions are deprecated and forced onto
Node 24. Bump every action to its current Node 24 major: checkout v7,
setup-python v7, upload-artifact v7, download-artifact v8, cache v6.

pre-commit.yml also drops the pre-commit/action wrapper: even its latest
release still pins the deprecated actions/cache internally, so run pre-commit
directly with an explicit cache keyed on .pre-commit-config.yaml -- the same
thing the wrapper did, without the warning.

The dormant conda-* workflows (workflow_dispatch-only, missing their recipe/
directory) are left untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.14 is a released CPython with wheels across the scientific stack, so it
joins the tested matrix and the declared classifiers together. 3.15 is still
at release-candidate stage: test it on ubuntu as an experimental
continue-on-error job (allow-prereleases) so breakage surfaces early, but
without declaring support or blocking the workflow. Promote it into the
matrix -- classifier and matrix entry together -- once it releases and
passes.

Restores the forward-version coverage the old cibuildwheel matrix listed as
cp314/cp315, this time actually running the test suite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The hook enforces the declared Python ceiling and was stripping the new 3.14
classifier (that is why the previous push failed pre-commit). 3.14 is now
tested and supported, so the pin moves with it. This file is the single knob
to bump alongside the workflow matrix when 3.15 releases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The lane cannot pass until the ecosystem ships cp315 wheels (h5py has none,
so pip falls into a doomed source build), and GitHub renders its
continue-on-error failure as a red X on the PR anyway. Test 3.15 when it
releases: matrix entry, classifier, and setup-cfg-fmt --max-py-version
together. Matrix stays 3.9-3.14.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Areustle Areustle changed the title ci: build a pure-Python distribution instead of 21 platform wheels ci: build a pure-Python distribution instead of platform-specific binary wheels Aug 27, 2026
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.

1 participant