From 60df7b8916294031cd6608b3bc6ea56a4c3bf83f Mon Sep 17 00:00:00 2001 From: elijahr <153711+elijahr@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:25:35 -0500 Subject: [PATCH 1/4] fix: ship complete sdist and add release verification gate - Add MANIFEST.in so the sdist includes the full test tree (helpers, fixtures, real_headers, regressions), scripts/, and docs needed to run the suite from the tarball - Ship autopxd/stubs/darwin-include/.supports-builtin-modules in both wheel and sdist (package-data globs skip leading-dot files) - Gate publishing on check-manifest and twine check --strict in the build job; add check-manifest pre-commit hook - Pin build-system setuptools>=61; bump version to 3.2.3 with changelog entry and release-process docs --- .github/workflows/publish.yml | 9 +++++++++ .pre-commit-config.yaml | 9 +++++++++ CHANGELOG.md | 26 +++++++++++++++++++++++++- CONTRIBUTING.md | 18 ++++++++++++++++++ MANIFEST.in | 33 +++++++++++++++++++++++++++++++++ pyproject.toml | 20 ++++++++++++++++++-- 6 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 MANIFEST.in diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0e00b99..338d6b6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,6 +37,15 @@ jobs: - name: Build sdist and wheel run: python -m build + - name: Install verification tools + run: uv pip install --system check-manifest twine + + - name: Verify sdist completeness + run: check-manifest --verbose + + - name: Validate distribution metadata + run: twine check --strict dist/* + - name: Upload distribution artifacts uses: actions/upload-artifact@v4 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8e58ee..bad4087 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,3 +24,12 @@ repos: additional_dependencies: - pycparser - click + + - repo: https://github.com/mgedmin/check-manifest + rev: "0.51" + hooks: + - id: check-manifest + args: [--no-build-isolation] + additional_dependencies: + - setuptools + - wheel diff --git a/CHANGELOG.md b/CHANGELOG.md index 69b3438..cac0185 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.2.3] - 2026-06-05 + +### Fixed +- **Incomplete source distribution** - The PyPI sdist now ships the full test + suite, including helper modules (`test/assertions.py`, `test/cython_utils.py`, + `test/conftest.py`, `test/header_cache.py`, `test/library_detection.py`), + fixtures, and data directories. Previously these were omitted, causing + `ModuleNotFoundError: No module named 'test.assertions'` when downstream + packagers ran the tests from the sdist (NixOS/nixpkgs#524341). The release + workflow now runs `check-manifest` and `twine check --strict` before publishing + so an incomplete sdist cannot ship again. + + Note for downstream packagers without network access: the `real_headers` tests + download library headers at runtime and must be deselected with + `pytest -m "not real_headers"`. +- **Missing runtime stub in wheel and sdist** - Ship + `autopxd/stubs/darwin-include/.supports-builtin-modules` in both the wheel and + the sdist. The `stubs/darwin-include/**/*` package-data glob silently skipped + leading-dot files, so this runtime include-tree stub was missing from every + previous wheel. + ## [3.2.2] - 2025-12-19 ### Fixed @@ -179,7 +200,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - macOS support -[Unreleased]: https://github.com/elijahr/python-autopxd2/compare/v3.2.0...HEAD +[Unreleased]: https://github.com/elijahr/python-autopxd2/compare/v3.2.3...HEAD +[3.2.3]: https://github.com/elijahr/python-autopxd2/compare/v3.2.2...v3.2.3 +[3.2.2]: https://github.com/elijahr/python-autopxd2/compare/v3.2.1...v3.2.2 +[3.2.1]: https://github.com/elijahr/python-autopxd2/compare/v3.2.0...v3.2.1 [3.2.0]: https://github.com/elijahr/python-autopxd2/compare/v3.1.1...v3.2.0 [3.1.1]: https://github.com/elijahr/python-autopxd2/compare/v3.1.0...v3.1.1 [3.1.0]: https://github.com/elijahr/python-autopxd2/compare/v3.0.0...v3.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9426155..bc890ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -158,6 +158,24 @@ This section is for project maintainers who can publish releases. git push origin master ``` +> **Important:** The git ref you release from (the tag, or the SHA passed to +> the manual `workflow_dispatch`) MUST contain the `pyproject.toml` version +> bump. `workflow_dispatch` accepts an arbitrary ref and will happily build +> and publish from a ref that lacks the bump. + +### Sdist completeness guard + +The publish workflow builds the sdist and wheel, then runs `check-manifest` +and `twine check --strict` **before** uploading the distribution artifacts. If +the sdist is missing any version-controlled file that belongs in it (for +example, a new test helper or fixture), `check-manifest` fails, the `build` +job fails, and because `publish-pypi` depends on `build`, nothing is published. + +`check-manifest` also runs locally via pre-commit, so drift is usually caught +before you push. If it flags a new file, update `MANIFEST.in` (to ship it) or +the `[tool.check-manifest]` `ignore` list in `pyproject.toml` (to keep it out +of the sdist) — never weaken the gate to make it pass. + ### 2. Create a GitHub Release 1. Go to [Releases](https://github.com/elijahr/python-autopxd2/releases) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..6555de2 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,33 @@ +# Sdist content spec. The wheel is unaffected (include_package_data is not set; +# packages are controlled by [tool.setuptools.packages.find]). +# Ship the complete test tree so downstream packagers (e.g. nixpkgs) can run the +# suite from the sdist. See NixOS/nixpkgs#524341. + +# --- Test suite: helpers, fixtures, and data (the fix) --- +recursive-include test *.py +recursive-include test *.test *.cpptest +recursive-include test *.h *.hpp *.pxd +recursive-include test *.gitkeep + +# --- Runtime stub dotfile dropped by setuptools globbing --- +# The "stubs/darwin-include/**/*" package-data glob does not match leading-dot +# files, so the sdist's default include misses this tracked stub. It is read at +# runtime (clang -I include path), so ship it explicitly. +include autopxd/stubs/darwin-include/.supports-builtin-modules + +# --- Top-level docs/metadata worth shipping in source form --- +include CHANGELOG.md +include CONTRIBUTING.md +include regenerate_stubs.py + +# --- Test-library install helpers referenced by test/test_real_headers.py --- +recursive-include scripts *.sh + +# --- Repo-only infrastructure: never ship --- +exclude .gitignore +exclude .dockerignore +exclude .pre-commit-config.yaml +exclude Dockerfile +exclude mkdocs.yml +prune .github +prune docs diff --git a/pyproject.toml b/pyproject.toml index abd7bf2..9a8fcd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = ["setuptools", "wheel"] +requires = ["setuptools>=61", "wheel"] build-backend = "setuptools.build_meta" [project] name = "autopxd2" -version = "3.2.2" +version = "3.2.3" description = "Automatically generate Cython pxd files from C headers" readme = "README.md" license = { file = "LICENSE" } @@ -67,6 +67,11 @@ autopxd = [ "stubs/include/**/*", "stubs/darwin-include/*", "stubs/darwin-include/**/*", + # Leading-dot files are not matched by the "*" globs above (setuptools + # mirrors shell semantics where "*" skips dotfiles). This stub is consumed + # at runtime via the clang -I include path (declarations.py / + # pycparser_backend.py), so it must ship in the wheel as well as the sdist. + "stubs/darwin-include/.supports-builtin-modules", ] [tool.ruff] @@ -120,3 +125,14 @@ markers = [ "libclang: tests/parameterizations using the libclang backend (includes C++ tests)", "real_headers: tests against real system libraries (requires library installation)", ] + +[tool.check-manifest] +ignore = [ + ".gitignore", + ".dockerignore", + ".pre-commit-config.yaml", + "Dockerfile", + "mkdocs.yml", + ".github/**", + "docs/**", +] From b98d894225ea802154a839468633134e6d1c2682 Mon Sep 17 00:00:00 2001 From: elijahr <153711+elijahr@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:33:06 -0500 Subject: [PATCH 2/4] ci: pin sdist verification tool versions in publish workflow --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 338d6b6..fbeafaa 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -38,7 +38,7 @@ jobs: run: python -m build - name: Install verification tools - run: uv pip install --system check-manifest twine + run: uv pip install --system check-manifest==0.51 twine==6.2.0 - name: Verify sdist completeness run: check-manifest --verbose From 63ef4431bfe9400ddf59ecf3aaf69c3a972c4588 Mon Sep 17 00:00:00 2001 From: elijahr <153711+elijahr@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:58:03 -0500 Subject: [PATCH 3/4] build: address review feedback on manifest and hook pins - Use graft for test/ and scripts/ instead of extension allowlists, with global-exclude for *.py[cod] and __pycache__ - Pin setuptools>=61 in check-manifest hook deps to match the build-system floor --- .pre-commit-config.yaml | 2 +- MANIFEST.in | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bad4087..f8e2ee5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,5 +31,5 @@ repos: - id: check-manifest args: [--no-build-isolation] additional_dependencies: - - setuptools + - setuptools>=61 - wheel diff --git a/MANIFEST.in b/MANIFEST.in index 6555de2..d631d56 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,10 +4,8 @@ # suite from the sdist. See NixOS/nixpkgs#524341. # --- Test suite: helpers, fixtures, and data (the fix) --- -recursive-include test *.py -recursive-include test *.test *.cpptest -recursive-include test *.h *.hpp *.pxd -recursive-include test *.gitkeep +# Ship the entire tracked test tree; byte-compiled cruft is excluded below. +graft test # --- Runtime stub dotfile dropped by setuptools globbing --- # The "stubs/darwin-include/**/*" package-data glob does not match leading-dot @@ -21,7 +19,7 @@ include CONTRIBUTING.md include regenerate_stubs.py # --- Test-library install helpers referenced by test/test_real_headers.py --- -recursive-include scripts *.sh +graft scripts # --- Repo-only infrastructure: never ship --- exclude .gitignore @@ -31,3 +29,7 @@ exclude Dockerfile exclude mkdocs.yml prune .github prune docs + +# --- Hygiene: keep graft from sweeping byte-compiled cruft --- +global-exclude *.py[cod] +global-exclude __pycache__ From a403dfce0ab428da32145e4a282dffb639059421 Mon Sep 17 00:00:00 2001 From: elijahr <153711+elijahr@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:08:09 -0500 Subject: [PATCH 4/4] build: drop ineffective __pycache__ exclude from MANIFEST.in global-exclude matches file paths, not directories; *.py[cod] already excludes the byte-compiled files inside __pycache__. --- MANIFEST.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index d631d56..e70fcc9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -30,6 +30,5 @@ exclude mkdocs.yml prune .github prune docs -# --- Hygiene: keep graft from sweeping byte-compiled cruft --- +# --- Hygiene: keep graft from sweeping byte-compiled files --- global-exclude *.py[cod] -global-exclude __pycache__