Skip to content

Skip the maturin wheel build when its script is unreachable (#211) - #217

Merged
leynos merged 5 commits into
mainfrom
fix/mutmut-baseline-maturin
Jul 31, 2026
Merged

Skip the maturin wheel build when its script is unreachable (#211)#217
leynos merged 5 commits into
mainfrom
fix/mutmut-baseline-maturin

Conversation

@leynos

@leynos leynos commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • Every scheduled mutation-testing run for cuprum has failed at the
    baseline since 2026-07-14: test_maturin_wheel_build_snapshot dies
    with Unable to find maturin script before mutmut generates any
    mutants, so no mutation testing has actually happened.
  • Root cause: the maturin PyPI package locates its own compiled
    binary by walking each sysconfig scheme's scripts directory keyed
    off the running interpreter's sys.prefix — not sys.path/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 still imports fine (via sys.path,
    so cargo/rustc and the existing toolchain_available() check all
    report success), but the overlay never received maturin's script, so
    the lookup comes up empty and the build subprocess exits 1.
  • Fix: add maturin_script_locatable() to tests/helpers/maturin.py,
    mirroring maturin's own lookup exactly, and skip
    test_maturin_wheel_build_snapshot with a precise reason when it
    reports the script unreachable. In every normal environment (CI,
    build-wheels.yml, local uv run pytest) sys.prefix matches the
    virtualenv 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:

  • The maturin binary genuinely is unreachable in mutmut's layered
    overlay (confirmed empirically below), so a pytest.skip with an
    exact reason is not a workaround — it is accurate diagnosis.
  • Excluding the test from mutmut's test selection would need a new
    [tool.mutmut] section in pyproject.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.
  • This keeps the wheel-build snapshot test exercising the real
    maturin build path in every environment that can actually complete
    it, per the issue's stated preference.

Review walkthrough

  • tests/helpers/maturin.py:
    adds _script_named_maturin_exists() and maturin_script_locatable(),
    which reproduce maturin.__main__.get_maturin_path()'s own
    sysconfig-based scan for a file named maturin under each scheme's
    scripts directory.
  • cuprum/unittests/test_maturin_build.py:
    test_maturin_wheel_build_snapshot now skips with a reason naming
    sys.prefix when the script can't be found, alongside the existing
    Rust-toolchain skip. Two new unit tests
    (test_maturin_script_locatable_true_when_script_present /
    _false_when_script_absent) pin the detector's behaviour by faking
    the sysconfig scheme lookup, independent of the real environment.
  • tests/helpers/maturin_wheel.py:
    new module. Rebasing onto main pulled in MaturinBuildError (Fix Command-Query Separation violations (#118) #144),
    which together with the new detector pushed tests/helpers/maturin.py
    past pylint's 400-line module limit. The wheel-artifact snapshot parsers
    (wheel_build_snapshot and its private helpers) move here;
    tests/helpers/maturin.py re-exports wheel_build_snapshot, so all
    import sites are unchanged.
  • docs/developers-guide.md: documents maturin_script_locatable()'s scope, how it differs from toolchain_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:

$ uv run --with mutmut==3.6.0 python -m pytest -x cuprum/unittests/test_maturin_build.py::test_maturin_wheel_build_snapshot
# before the fix:
subprocess.CalledProcessError: Command '[...python', '-m', 'maturin', 'build', ...]' returned non-zero exit status 1.
Unable to find `maturin` script
1 failed in 0.14s

# after the fix:
cuprum/unittests/test_maturin_build.py::test_maturin_wheel_build_snapshot SKIPPED
SKIPPED [1] ...: maturin's compiled script is not locatable via this interpreter's
sysconfig scripts directories (sys.prefix='/home/leynos/.cache/uv/builds-v0/.tmp...');
this is expected in layered/ephemeral interpreters such as a `uv run --with ...` overlay.

Confirmed the fix does not mask a real build in normal environments:

$ uv run pytest -rs cuprum/unittests/test_maturin_build.py::test_maturin_wheel_build_snapshot -v
cuprum/unittests/test_maturin_build.py::test_maturin_wheel_build_snapshot PASSED
1 passed in 9.80s

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 full
    cuprum/unittests/test_maturin_build.py file (14 passed). One
    pre-existing Rust trybuild UI fixture
    (cuprum-rust::compile_tests::compile_time_ui,
    tests/ui/fail/const_availability_export.rs) fails on a rustc
    diagnostic-wording drift unrelated to this change; confirmed it also
    fails identically on an unmodified origin/main checkout.

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 — full
    file green, real build still exercised in a normal virtualenv.
  • make check-fmt, make lint, make typecheck — pass.
  • CI: watch the PR checks and the next scheduled mutation-testing
    run.

References

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:

  • Prevent mutation-testing runs from failing early by conditionally skipping the maturin wheel-build snapshot test when maturin’s script cannot be found in the current interpreter’s sysconfig scripts directories.

Enhancements:

  • Add a helper to detect whether maturin’s compiled script is discoverable in the current environment, mirroring maturin’s own lookup.
  • Refactor wheel artifact snapshot logic into a dedicated helper module and re-export its main entry point to preserve existing imports.

Tests:

  • Add unit tests covering maturin script discoverability in environments where the script is present or absent.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 338e988a-1429-4d52-9bd6-a4b403bd5f56

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Summary

  • Skip test_maturin_wheel_build_snapshot when the maturin script is not locatable through the running interpreter’s sysconfig script directories.
  • Add tests for POSIX scripts, missing scripts, Windows .exe launchers, and wheels without METADATA.
  • Move wheel snapshot parsing to tests/helpers/maturin_wheel.py and preserve the existing import path through re-exporting.
  • Document the difference between maturin script availability and general toolchain availability.
  • Keep native-wheel shell-out tests dependent on both availability checks.

Formatting, linting, type checking, and Python tests pass. An unrelated pre-existing Rust UI fixture failure remains.

Walkthrough

Extract 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.

Changes

Maturin build contracts

Layer / File(s) Summary
Wheel snapshot extraction
tests/helpers/maturin_wheel.py, tests/helpers/maturin.py, cuprum/unittests/test_maturin_build.py, docs/developers-guide.md
Move wheel metadata parsing and archive normalisation into wheel_build_snapshot. Define typed snapshot contracts. Re-export the helper and test missing METADATA handling.
Maturin script detection and build gating
tests/helpers/maturin.py, cuprum/unittests/test_maturin_build.py, docs/developers-guide.md
Add sysconfig-based detection for maturin and maturin.exe. Test present and absent scripts. Skip native-wheel tests when the script is not locatable. Document the lookup and skip boundary.

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
Loading

Possibly related PRs

  • leynos/cuprum#144: Shares the maturin wheel-build helper and extends the snapshot behaviour introduced there.
  • leynos/cuprum#224: Shares wheel snapshot updates and developer-guide changes.
  • leynos/cuprum#240: Extends the same maturin helper and wheel snapshot functionality.

Suggested labels: Issue

Suggested reviewers: codescene-access

Poem

Wheels parse,
Scripts resolve,
Metadata stands.
Tests guard the path,
Builds skip when needed.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning, 4 inconclusive)

Check name Status Explanation Resolution
Testing (Overall) ❌ Error The tests cover detector results and missing METADATA, but no test exercises the native-wheel skip gate; an unconditional skip or an unwired detector would still pass. Add deterministic tests for the caller: force the detector false and assert pytest.skip without a build, then force it true and assert the build runs; cover multiple schemes and non-file entries.
Testing (Property / Proof) ⚠️ Warning Recommend Hypothesis coverage: maturin_script_locatable() ranges over schemes, recursive paths and launcher stems, but the changed tests cover only three fixed fixtures. Add a Hypothesis test that generates multiple schemes, directories, irrelevant files and launcher suffixes, then verifies detection iff a regular file has stem maturin.
Testing (Unit And Behavioural) ❓ Inconclusive I am still checking the detector tests and the native wheel boundary against the implementation. Gather the remaining implementation and test evidence before deciding.
Unit Architecture ❓ Inconclusive Initial inspection found a potentially hidden fallibility boundary in the boolean filesystem probe; verify its exact failure behaviour and intended policy before deciding. Inspect the detector's filesystem error paths and repository architecture guidance.
Security And Privacy ❓ Inconclusive Investigation has not started; no verdict evidence is available yet. Inspect the changed files and their new parsing, path lookup, skip diagnostics, and documentation before deciding.
Performance And Resource Use ❓ Inconclusive Investigation is still in progress; no final assessment submitted. Gather repository evidence before deciding.
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises skipping the maturin wheel build when its script is unreachable and links issue #211.
Description check ✅ Passed The description clearly explains the root cause, implementation, refactoring, tests, and validation for the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
User-Facing Documentation ✅ Passed Treat this check as not applicable: the patch changes only test helpers/tests and docs/developers-guide.md; it adds no end-user API or runtime behaviour, and docs/users-guide.md is unchanged.
Developer Documentation ✅ Passed Pass this check: docs/developers-guide.md documents the new helper, wheel-parser module boundary, re-export, skip conditions, tooling distinction, and reuse policy; no roadmap or execplan update is...
Module-Level Documentation ✅ Passed Accept the documentation: all three changed Python modules have module docstrings; maturin_wheel.py also states its parsing scope and re-export relationship.
Testing (Compile-Time / Ui) ✅ Passed Accept this check: the PR changes no Rust or TypeScript files, and the wheel output uses a focused syrupy snapshot with stable, meaningful metadata and entry assertions.
Domain Architecture ✅ Passed Keep the change: maturin, sysconfig, filesystem, subprocess, and ZIP logic stays in tests/helpers; no production cuprum module imports these helpers or gains infrastructure concerns.
Observability ✅ Passed Accept this check: the PR changes only test helpers, tests, and docs; pytest.skip reports the failure boundary and sys.prefix, with no production telemetry requirement triggered.
Concurrency And State ✅ Passed Accept this check: the change is synchronous and uses local path/archive state; it adds no shared mutable state, async tasks, locks, cancellation, or ordering protocol requiring concurrency tests.
Architectural Complexity And Maintainability ✅ Passed Keep this change: the wheel parser has a cohesive module boundary, the re-export preserves imports, docs state reuse, and static inspection found no new dependency cycle or heavy mechanism.
Rust Compiler Lint Integrity ✅ Passed The PR changes only Python and Markdown files; no Rust paths, lint suppressions, artificial usage anchors, or new clone calls were added.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mutmut-baseline-maturin

Comment @coderabbitai help to get the list of available commands.

@lodyai
lodyai Bot force-pushed the fix/mutmut-baseline-maturin branch from 679ce9d to 3511d5d Compare July 28, 2026 09:42
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review July 28, 2026 09:55
@sourcery-ai

sourcery-ai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds 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

Change Details Files
Add a sysconfig-based detector for maturin’s compiled script and use it to conditionally skip the wheel-build snapshot test when the script cannot be located by the running interpreter.
  • Introduce _script_named_maturin_exists and maturin_script_locatable in the maturin test helper module, mirroring maturin.main.get_maturin_path’s sysconfig-based scan of scheme scripts directories rooted at sys.prefix/sys.exec_prefix.
  • Update test_maturin_wheel_build_snapshot to call maturin_script_locatable and skip with a detailed reason including sys.prefix when the maturin script is unreachable, in addition to the existing Rust toolchain availability skip.
  • Add two unit tests that monkeypatch sysconfig.get_scheme_names and sysconfig.get_path to assert maturin_script_locatable returns True when a maturin script file is present in a scheme’s scripts dir and False when it is absent, modeling the uv run --with overlay case.
tests/helpers/maturin.py
cuprum/unittests/test_maturin_build.py
Extract wheel-artifact snapshot parsing into a dedicated helper module and re-export its main entry point to keep callers stable while satisfying linting constraints.
  • Move wheel metadata/entry parsing helpers (including _GENERATOR_RE, _EXTENSION_MODULE_RE, _DIST_INFO_SUFFIXES, _header_value, _parse_metadata, _normalise_wheel_entry, _locate_dist_info_wheel, _parse_wheel_header, and wheel_build_snapshot) from the maturin helper module into a new tests/helpers/maturin_wheel.py module focused on built-wheel inspection.
  • Adjust imports in tests/helpers/maturin.py to consume tests.helpers.maturin_wheel and re-export wheel_build_snapshot so existing import sites remain unchanged despite the refactor.
  • Simplify typing-related imports in tests/helpers/maturin.py (using pathlib.Path at runtime instead of TYPE_CHECKING guards) now that wheel-oriented typing helpers have moved out.
tests/helpers/maturin.py
tests/helpers/maturin_wheel.py

Assessment against linked issues

Issue Objective Addressed Explanation
#211 Ensure the mutation-testing baseline job no longer fails on test_maturin_wheel_build_snapshot with "Unable to find maturin script" in the uv run --with mutmut==3.6.0 overlay environment.
#211 Adjust the maturin wheel build test/helpers so that the real maturin build path is still exercised in normal environments where the maturin script is available, rather than being blanket-disabled.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread tests/helpers/maturin.py
@coderabbitai coderabbitai Bot added the Issue label Jul 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between b0ef9a9 and 3511d5d.

📒 Files selected for processing (3)
  • cuprum/unittests/test_maturin_build.py
  • tests/helpers/maturin.py
  • tests/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)

Comment thread tests/helpers/maturin_wheel.py Outdated
Comment thread tests/helpers/maturin.py
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between b0ef9a9 and e71ab57.

📒 Files selected for processing (4)
  • cuprum/unittests/test_maturin_build.py
  • docs/developers-guide.md
  • tests/helpers/maturin.py
  • tests/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)

Comment thread cuprum/unittests/test_maturin_build.py Outdated
Comment thread tests/helpers/maturin_wheel.py Outdated
@lodyai
lodyai Bot force-pushed the fix/mutmut-baseline-maturin branch from e71ab57 to 4f0cf31 Compare July 29, 2026 09:41
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai is this request proportionate to the risk inherent in the implementation?

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Testing (Property / Proof) ⚠️ Warning maturin_script_locatable() spans many scheme/path/name combinations, but the PR adds only example tests; no property test or proof exercises the invariant. Add a Hypothesis property test over sysconfig schemes and script names/paths (including stem-based Windows launchers), or justify a bounded proof if you want exhaustive coverage.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

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.py

Length 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


@leynos: Treat the property/proof warning as disproportionate to this change’s risk. I withdraw it.

maturin_script_locatable() is a small existential predicate: scan existing script directories and return true when any regular file has stem maturin. The committed tests already cover the meaningful behavioural partitions:

  • a POSIX maturin launcher is found;
  • an existing overlay script directory without maturin returns false—the reported mutmut failure mode;
  • a Windows maturin.exe launcher is accepted through stem matching.

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 maturin.exe or a missing scheme directory; do not require Hypothesis or a proof for this helper.

ʕᵔᴥᵔʔ

You are interacting with an AI system.

@leynos

leynos commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between e71ab57 and 4f0cf31.

📒 Files selected for processing (4)
  • cuprum/unittests/test_maturin_build.py
  • docs/developers-guide.md
  • tests/helpers/maturin.py
  • tests/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)

Comment thread tests/helpers/maturin_wheel.py
Comment thread tests/helpers/maturin_wheel.py
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos

leynos commented Jul 31, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

leynos and others added 5 commits July 31, 2026 18:52
`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.
@lodyai
lodyai Bot force-pushed the fix/mutmut-baseline-maturin branch from f37aa8b to afe4359 Compare July 31, 2026 16:55
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No quality gates enabled for this code.

@leynos
leynos merged commit 829b6b4 into main Jul 31, 2026
21 checks passed
@leynos
leynos deleted the fix/mutmut-baseline-maturin branch July 31, 2026 19:24
@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mutation-testing baseline fails: maturin wheel build cannot find its own script

3 participants