Skip the maturin wheel build when its script is unreachable (#211) - #217
Conversation
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Summary
Formatting, linting, type checking, and Python tests pass. An unrelated pre-existing Rust UI fixture failure remains. WalkthroughExtract wheel snapshot parsing into a dedicated helper. Re-export it through the existing maturin helper. Add sysconfig-based script detection, platform-specific tests, documentation, and a skip guard for unavailable maturin scripts. ChangesMaturin build contracts
Sequence Diagram(s)sequenceDiagram
participant WheelBuildTest
participant maturin_script_locatable
participant sysconfig
participant ScriptsDirectory
WheelBuildTest->>maturin_script_locatable: check script availability
maturin_script_locatable->>sysconfig: read script directories
sysconfig-->>maturin_script_locatable: return configured paths
maturin_script_locatable->>ScriptsDirectory: search for maturin stem
ScriptsDirectory-->>maturin_script_locatable: report presence or absence
maturin_script_locatable-->>WheelBuildTest: return boolean
WheelBuildTest->>WheelBuildTest: skip or run wheel snapshot test
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (1 error, 1 warning, 4 inconclusive)
✅ Passed checks (14 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
679ce9d to
3511d5d
Compare
Reviewer's GuideAdds an environment-aware detector for maturin’s compiled script so the maturin wheel snapshot test can skip in layered interpreters where the script is genuinely unreachable, and factors wheel snapshot parsing into a dedicated helper module while preserving existing imports. File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3511d5d78c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/helpers/maturin_wheel.py`:
- Line 40: Replace the dict[str, typ.Any] return type of _parse_metadata with a
TypedDict describing the fixed snapshot fields generator, metadata, wheel, and
entries, using their concrete value types. Update the parsed snapshot
construction and the test_maturin_wheel_build_snapshot call site as needed so
indexing snapshot_payload["generator"] and the other fields is statically typed
without Any.
In `@tests/helpers/maturin.py`:
- Around line 210-248: Update _script_named_maturin_exists to check only for the
exact maturin launcher file directly in the given scripts directory, removing
the recursive rglob/stem-based match that accepts decoy files such as
maturin.exe or nested entries. Add a regression test using a decoy file to
verify maturin_script_locatable does not report success when the exact launcher
is absent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 5cf77047-b92a-481e-855f-4a5f30b06794
📒 Files selected for processing (3)
cuprum/unittests/test_maturin_build.pytests/helpers/maturin.pytests/helpers/maturin_wheel.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
leynos/shared-actions(auto-detected)leynos/pylint-pypy-shim(auto-detected)leynos/whitaker(auto-detected)
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cuprum/unittests/test_maturin_build.py`:
- Line 73: Update both assertions in the maturin launcher-discovery tests,
including the assertion in the test containing maturin_script_locatable(), to
include descriptive failure messages identifying the expected launcher-discovery
outcome; preserve the existing assertion conditions.
In `@tests/helpers/maturin_wheel.py`:
- Line 33: Update the docstrings in tests/helpers/maturin_wheel.py at the
affected locations, including the prose associated with the metadata snapshot,
to use “normalized” instead of “normalised”; preserve all identifiers and other
wording.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a9fbc6eb-4724-4b04-a253-349c20c1f08f
📒 Files selected for processing (4)
cuprum/unittests/test_maturin_build.pydocs/developers-guide.mdtests/helpers/maturin.pytests/helpers/maturin_wheel.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
leynos/shared-actions(auto-detected)leynos/pylint-pypy-shim(auto-detected)leynos/whitaker(auto-detected)
e71ab57 to
4f0cf31
Compare
|
@coderabbitai is this request proportionate to the risk inherent in the implementation? ❌ Failed checks (1 warning)
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
ast-grep outline tests/helpers/maturin.py --items all --type function
ast-grep outline unittests/test_maturin_build.py --items all --type function --match 'maturin|wheel'
printf '\n--- helper implementation ---\n'
rg -n -A80 -B8 'def (_script_named_maturin_exists|maturin_script_locatable)\b' tests/helpers/maturin.py
printf '\n--- direct detector tests ---\n'
rg -n -A65 -B8 'def test_maturin_script_locatable\b' unittests/test_maturin_build.pyLength of output: 5677 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- detector test locations and implementations ---'
rg -n -A75 -B8 '^def test_maturin_script_locatable' .
printf '%s\n' '--- Hypothesis usage and dependency declarations ---'
rg -n -i -C2 'hypothesis' \
-g 'pyproject.toml' -g 'uv.lock' -g 'requirements*.txt' -g 'tox.ini' -g 'pytest.ini' -g '*.py' . || true
printf '%s\n' '--- relevant test module names ---'
fd -t f '.*maturin.*\.py$' .Length of output: 40883
Generating arbitrary scheme names, path strings, and launcher names would mostly exercise a mocked filesystem/sysconfig arrangement and duplicate the implementation’s predicate. It would neither validate maturin’s actual lookup nor materially reduce the only practical consequence here: an incorrectly skipped test. Keep the focused examples. Add, only if desired for branch completeness, one deterministic case containing a nested ʕᵔᴥᵔʔ You are interacting with an AI system. |
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/helpers/maturin_wheel.py`:
- Around line 162-173: Update the documented interfaces across
tests/helpers/maturin_wheel.py:162-173 by adding NumPy-style Parameters and
Returns sections to wheel_build_snapshot; tests/helpers/maturin_wheel.py:32-55
by providing structured documentation for the exported snapshot TypedDict types;
and tests/helpers/maturin_wheel.py:101-159 by replacing boilerplate
private-helper Parameters and Raises sections with concise single-line summaries
while retaining only non-obvious guarantees. Also add a Returns section to
maturin_script_locatable in tests/helpers/maturin.py:217-239, keeping public
interfaces fully documented and private helpers concise.
- Around line 177-179: Update the metadata-reading logic near wheel_payload and
metadata_payload to validate that metadata_name exists in the archive before
calling archive.read(metadata_name). Raise the helper’s documented
AssertionError when the METADATA member is absent, while preserving the existing
decoding behavior when it is present.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 95f09f00-d436-4509-8eec-d375bc6a381d
📒 Files selected for processing (4)
cuprum/unittests/test_maturin_build.pydocs/developers-guide.mdtests/helpers/maturin.pytests/helpers/maturin_wheel.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
leynos/shared-actions(auto-detected)leynos/pylint-pypy-shim(auto-detected)leynos/whitaker(auto-detected)
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
`test_maturin_wheel_build_snapshot` fails every scheduled mutmut run: `sys.executable -m maturin build` dies with "Unable to find `maturin` script" before any mutants are generated, aborting the whole baseline. The `maturin` PyPI package resolves its own compiled binary by walking each `sysconfig` scheme's `scripts` directory keyed off the running interpreter's `sys.prefix`, not `sys.path` or `PATH`. Under mutmut's `uv run --with mutmut==3.6.0` overlay, `sys.prefix` points at a temporary environment layered on top of the project's own virtualenv: the `maturin` module imports fine (via `sys.path`, so `cargo`/`rustc` and `toolchain_available()` all report success), but the overlay never received maturin's script, so the lookup comes up empty. Add `maturin_script_locatable()` to `tests/helpers/maturin.py`, mirroring maturin's own lookup, and skip the wheel-build test with a precise reason when it reports the script unreachable. In a normal virtualenv (CI, `build-wheels.yml`, local `uv run pytest`) `sys.prefix` matches the install location, the script is found, and the real build still runs — only the layered mutmut overlay skips. Add unit tests pinning the new detector's true/false behaviour by faking the `sysconfig` scheme lookup. Rebasing onto main brought in `MaturinBuildError` (#144), which — combined with the new `maturin_script_locatable()` detector — pushed `tests/helpers/maturin.py` past pylint's 400-line module limit. Extract the wheel-artifact snapshot parsers (`wheel_build_snapshot` and its private helpers) into a new sibling module `tests/helpers/maturin_wheel.py`, and re-export `wheel_build_snapshot` from `tests/helpers/maturin.py` so existing import sites are unchanged.
Record the scope and reuse policy for the shared `maturin_script_locatable()` detector in the developers' guide, as the abstraction/helper policy in AGENTS.md requires. The helper now decides when the native-wheel build contract is skipped, so document: - how it mirrors maturin's own `sysconfig`-scheme script lookup keyed off `sys.prefix`, and why that is deliberately narrower than `toolchain_available()`'s importability probe; - the layered/ephemeral interpreter case (the `uv run --with mutmut` overlay) where the two checks disagree and the skip is genuine, versus normal virtualenvs where the real build still runs; - the reuse policy: tests that shell out to `python -m maturin build` should gate on both `toolchain_available()` and `maturin_script_locatable()`; import-only or pin/metadata tests should not; extend the helper in place rather than re-deriving the scan. Also note that the wheel-artefact snapshot parsers now live in `tests/helpers/maturin_wheel.py` (re-exported from `tests/helpers/maturin.py`), matching the module split.
Replace the `dict[str, typ.Any]` returns in `tests/helpers/maturin_wheel.py` with `TypedDict`s describing the fixed snapshot shape: `WheelBuildSnapshot` (`generator`, `metadata`, `wheel`, `entries`), plus `WheelMetadata` and `WheelHeaders` for the nested payloads. Indexing `snapshot_payload["generator"]` at the `test_maturin_wheel_build_snapshot` call site is now statically typed without `Any`; `TypedDict` is a plain dict at runtime, so the syrupy snapshot comparison is unchanged. Also pin the deliberate stem-based, recursive matching in `_script_named_maturin_exists` with a regression test. maturin's own `get_maturin_path` walks the scripts directory with `os.walk` and compares `os.path.splitext(f)[0]` against `"maturin"`, so it accepts any extension at any depth; `maturin.exe` is the real launcher on the `windows-2022` wheel target. Narrowing the match to an exact top-level `maturin` filename would diverge from maturin and make the probe report unavailable on Windows, silently skipping the native-wheel contract there.
Give both remaining bare assertions in the maturin launcher-discovery tests descriptive failure messages naming the expected outcome, matching the style already used by the Windows-launcher test and the rest of the module. The assertion conditions are unchanged. Switch the `-ised` docstring prose in `tests/helpers/maturin_wheel.py` to the `-ized` Oxford endings the documentation style guide requires (`docs/documentation-style-guide.md`, en-GB-oxendict), matching the `_normalise_wheel_entry` docstring that already read "Normalize". Identifiers keep their existing spelling, so `_normalise_wheel_entry` and the `normalised` loop variable are untouched.
`wheel_build_snapshot` derived the `.dist-info/METADATA` entry name from the WHEEL entry by string substitution and passed it straight to `ZipFile.read`, which raises `KeyError` for an absent member. That contradicted the documented `Raises` contract, which advertises only `AssertionError`, `OSError`, and `zipfile.BadZipFile`. Check archive membership first and raise `AssertionError`, matching the existing `_locate_dist_info_wheel` precedent for a missing WHEEL entry, and cover it with `test_wheel_build_snapshot_rejects_wheel_without_metadata`. Bring the module's docstrings into line with the docstring-structure policy in `docs/developers-guide.md`, which requires comprehensive NumPy-style docstrings for public symbols and prefers single-line summaries for private helpers: - add Parameters and Returns sections to `wheel_build_snapshot`, and widen its AssertionError entry to cover the new METADATA check; - document every field of the public `WheelMetadata`, `WheelHeaders`, and `WheelBuildSnapshot` TypedDicts with Attributes sections; - reduce `_locate_dist_info_wheel` and `_parse_wheel_header` to single-line summaries, dropping sections that only restated their signatures; - add a Returns section to `maturin_script_locatable`, keeping its explanatory prose, which records genuinely non-obvious behaviour.
f37aa8b to
afe4359
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
cuprumhas failed at thebaseline since 2026-07-14:
test_maturin_wheel_build_snapshotdieswith
Unable to findmaturinscriptbefore mutmut generates anymutants, so no mutation testing has actually happened.
maturinPyPI package locates its own compiledbinary by walking each
sysconfigscheme'sscriptsdirectory keyedoff the running interpreter's
sys.prefix— notsys.path/PATH.Under mutmut's
uv run --with mutmut==3.6.0overlay,sys.prefixpoints at a temporary environment layered on top of the project's own
virtualenv: the
maturinmodule still imports fine (viasys.path,so
cargo/rustcand the existingtoolchain_available()check allreport success), but the overlay never received maturin's script, so
the lookup comes up empty and the build subprocess exits 1.
maturin_script_locatable()totests/helpers/maturin.py,mirroring maturin's own lookup exactly, and skip
test_maturin_wheel_build_snapshotwith a precise reason when itreports the script unreachable. In every normal environment (CI,
build-wheels.yml, localuv run pytest)sys.prefixmatches thevirtualenv that installed the script, so the real native build still
runs unchanged — only the layered mutmut overlay skips.
Closes #211
Why this design over the alternatives
The issue proposed two paths: exclude the test from mutmut's baseline
selection, or make the test locate maturin robustly and skip only when
genuinely unavailable. This PR takes the second path because it is the
more precise fix for the actual root cause:
overlay (confirmed empirically below), so a
pytest.skipwith anexact reason is not a workaround — it is accurate diagnosis.
[tool.mutmut]section inpyproject.toml(there currently is none;mutmut runs on defaults) and would silence the test everywhere
mutmut runs, even in environments where the build would actually
succeed.
maturin buildpath in every environment that can actually completeit, per the issue's stated preference.
Review walkthrough
tests/helpers/maturin.py:adds
_script_named_maturin_exists()andmaturin_script_locatable(),which reproduce
maturin.__main__.get_maturin_path()'s ownsysconfig-based scan for a file namedmaturinunder each scheme'sscriptsdirectory.cuprum/unittests/test_maturin_build.py:test_maturin_wheel_build_snapshotnow skips with a reason namingsys.prefixwhen the script can't be found, alongside the existingRust-toolchain skip. Two new unit tests
(
test_maturin_script_locatable_true_when_script_present/_false_when_script_absent) pin the detector's behaviour by fakingthe
sysconfigscheme lookup, independent of the real environment.tests/helpers/maturin_wheel.py:new module. Rebasing onto
mainpulled inMaturinBuildError(Fix Command-Query Separation violations (#118) #144),which together with the new detector pushed
tests/helpers/maturin.pypast pylint's 400-line module limit. The wheel-artifact snapshot parsers
(
wheel_build_snapshotand its private helpers) move here;tests/helpers/maturin.pyre-exportswheel_build_snapshot, so allimport sites are unchanged.
docs/developers-guide.md: documentsmaturin_script_locatable()'s scope, how it differs fromtoolchain_available(), the native-wheel skip boundary, and the reuse policy (which tests should gate on it), per the AGENTS.md abstraction/helper policy.Validation evidence
Reproduced the exact CI failure locally, then confirmed the fix:
Confirmed the fix does not mask a real build in normal environments:
Gates run against the two changed files (
make build,make check-fmt,make lint,make typecheck,make test):build,check-fmt,lint,typecheck: pass.test: all Python suites pass, including the fullcuprum/unittests/test_maturin_build.pyfile (14 passed). Onepre-existing Rust
trybuildUI fixture(
cuprum-rust::compile_tests::compile_time_ui,tests/ui/fail/const_availability_export.rs) fails on a rustcdiagnostic-wording drift unrelated to this change; confirmed it also
fails identically on an unmodified
origin/maincheckout.Test plan
uv run --with mutmut==3.6.0 python -m pytest -x cuprum/unittests/test_maturin_build.py— reproduced the failure,then confirmed the skip.
uv run pytest cuprum/unittests/test_maturin_build.py— fullfile green, real build still exercised in a normal virtualenv.
make check-fmt,make lint,make typecheck— pass.run.
References
baseline fails: maturin wheel build cannot find its own script.
Summary by Sourcery
Skip the maturin wheel-build snapshot test when maturin’s compiled script is not locatable by the running interpreter, while keeping normal builds exercised and reorganising wheel snapshot helpers into a dedicated module.
Bug Fixes:
Enhancements:
Tests: