Skip to content

feat(wheels): add configurable build tag hook for wheel filenames - #1273

Open
jlarkin09 wants to merge 1 commit into
python-wheel-build:mainfrom
jlarkin09:feat/wheel-build-tag-hook-1181
Open

feat(wheels): add configurable build tag hook for wheel filenames#1273
jlarkin09 wants to merge 1 commit into
python-wheel-build:mainfrom
jlarkin09:feat/wheel-build-tag-hook-1181

Conversation

@jlarkin09

@jlarkin09 jlarkin09 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Implement the accepted proposal from docs/proposals/wheel-build-tag-hook.md (issue #1059, tracking issue #1181).

Add a wheels.build_tag_hook option in global settings that lets downstream projects append environment-specific suffixes (OS, accelerator, torch ABI) to wheel build tags via a user-defined callable. The hook receives ctx, req, version, and wheel_tags and returns suffix segments joined with _.

  • Add WheelSettings model with build_tag_hook: ImportString to settings
  • Add get_build_tag() and _validate_build_tag_segments() to wheels.py
  • Update add_extra_metadata_to_wheels(), bootstrapper cache checks, and _is_wheel_built() to use computed build tags
  • Minimal finder update to match suffixed build tag filenames
  • Validate hook output: reject single strings, invalid chars, non-strings
  • No behavior change when hook is not configured

Continues on PR: #1217
Closes: #1181

@jlarkin09
jlarkin09 requested a review from a team as a code owner July 24, 2026 21:55
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds global wheels.build_tag_hook settings and the WheelSettings model. Implements validated build-tag suffix generation and applies it during wheel metadata creation. Cache lookup, cache downloads, prebuilt-wheel checks, and wheel filename discovery now use computed build tags, including suffixed variants. Tests cover configuration parsing, hook behavior, validation errors, and matching cases.

Estimated code review effort: 3 (Moderate) | ~30 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding a configurable wheel build-tag hook.
Description check ✅ Passed The description matches the changeset and accurately summarizes the new wheel build-tag hook work.
Linked Issues check ✅ Passed The changes implement the wheel_build_tag hook, validation, settings, and cache/finder updates required by #1181.
Out of Scope Changes check ✅ Passed The file changes are all directly tied to the build-tag hook feature and its matching logic.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@mergify mergify Bot added the ci label Jul 24, 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: 1

🧹 Nitpick comments (2)
src/fromager/packagesettings/_models.py (1)

48-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Docstring omits an important behavioral gotcha.

wheels.get_build_tag() skips the hook entirely when the package's base build tag is empty (no changelog build-tag bump for that version). Worth documenting here so hook authors don't expect it to fire unconditionally. Also worth stating the determinism requirement mentioned in the PR description (hook must not depend on wheel contents/build env/ELF info) since nothing enforces it in code.

📝 Suggested docstring addition
     """Callable that returns suffix segments for the wheel build tag.
 
     The callable receives keyword-only arguments ``ctx``, ``req``,
     ``version``, and ``wheel_tags`` and returns
     ``Sequence[str]`` of suffix segments.
 
+    Only invoked when the package already has a non-empty build tag
+    from its changelog entry for the given version; otherwise the hook
+    is skipped and no build tag is added. The callable must be
+    deterministic and independent of wheel contents, build environment,
+    or ELF metadata so fresh builds and cache lookups compute the same
+    tag.
+
     .. versionadded:: 0.92.0
     """
🤖 Prompt for 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.

In `@src/fromager/packagesettings/_models.py` around lines 48 - 58, Update the
build_tag_hook docstring to document that wheels.get_build_tag() does not invoke
the hook when the package’s base build tag is empty, and state that hook results
must be deterministic and independent of wheel contents, build environment, and
ELF information.
tests/test_wheels.py (1)

374-440: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing edge-case coverage: hook skip + call-argument verification.

No test verifies (1) the hook is not invoked when the package has no base build tag, and (2) the hook receives the correct ctx/req/version/wheel_tags values — both are explicit contract points for this feature.

def test_hook_not_called_without_base_tag(self, tmp_path: pathlib.Path) -> None:
    """Hook is skipped entirely when the package has no changelog build tag."""
    from packaging.tags import Tag

    calls = []

    def hook(**kwargs: object) -> list[str]:
        calls.append(kwargs)
        return ["el9.6"]

    ctx = _ctx_with_hook(tmp_path, hook=hook)
    req = Requirement("mypkg")  # no changelog entry -> base tag is ()
    version = Version("1.0")
    tags = frozenset({Tag("cp312", "cp312", "linux_x86_64")})
    result = wheels.get_build_tag(ctx=ctx, req=req, version=version, wheel_tags=tags)
    assert result == ()
    assert calls == []

As per path instructions, "Verify test actually tests the intended behavior. Check for missing edge cases."

🤖 Prompt for 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.

In `@tests/test_wheels.py` around lines 374 - 440, Extend the get_build_tag tests
to cover both contract edges: configure a hook through _ctx_with_hook for a
package with no base build tag, assert the result is empty, and verify the hook
is never called; also add call-argument assertions for a non-empty base-tag
case, confirming the hook receives the exact ctx, req, version, and wheel_tags
values used by get_build_tag.

Source: Path instructions

🤖 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/test_wheels.py`:
- Around line 342-488: Move the repeated packaging.tags.Tag and
fromager.packagesettings Settings, SettingsFile, and WheelSettings imports to
the module-level import section of tests/test_wheels.py. Remove the
corresponding local imports from _ctx_with_hook and every TestGetBuildTag
method, preserving their existing usage.

---

Nitpick comments:
In `@src/fromager/packagesettings/_models.py`:
- Around line 48-58: Update the build_tag_hook docstring to document that
wheels.get_build_tag() does not invoke the hook when the package’s base build
tag is empty, and state that hook results must be deterministic and independent
of wheel contents, build environment, and ELF information.

In `@tests/test_wheels.py`:
- Around line 374-440: Extend the get_build_tag tests to cover both contract
edges: configure a hook through _ctx_with_hook for a package with no base build
tag, assert the result is empty, and verify the hook is never called; also add
call-argument assertions for a non-empty base-tag case, confirming the hook
receives the exact ctx, req, version, and wheel_tags values used by
get_build_tag.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e8030f0f-912e-408f-b107-c1a722aaac6c

📥 Commits

Reviewing files that changed from the base of the PR and between d249228 and 5b89a26.

📒 Files selected for processing (10)
  • src/fromager/bootstrapper/_cache.py
  • src/fromager/commands/build.py
  • src/fromager/finders.py
  • src/fromager/packagesettings/__init__.py
  • src/fromager/packagesettings/_models.py
  • src/fromager/packagesettings/_settings.py
  • src/fromager/wheels.py
  • tests/test_finders.py
  • tests/test_packagesettings.py
  • tests/test_wheels.py

Comment thread tests/test_wheels.py
@jlarkin09
jlarkin09 force-pushed the feat/wheel-build-tag-hook-1181 branch 2 times, most recently from 6445684 to 5409eae Compare July 27, 2026 14:53
@jlarkin09
jlarkin09 requested review from shifa-khan and tiran July 27, 2026 16:06
@mergify

mergify Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be merged.
@jlarkin09 please rebase your branch.

@jlarkin09
jlarkin09 force-pushed the feat/wheel-build-tag-hook-1181 branch from 5409eae to 6f17876 Compare July 28, 2026 13:05
@rd4398

rd4398 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@jlarkin09 The CI is failing here and this also needs rebase. Can you please rebase it?

@jlarkin09
jlarkin09 force-pushed the feat/wheel-build-tag-hook-1181 branch from 6f17876 to c65d608 Compare July 29, 2026 20:33

@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: 1

🤖 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 `@src/fromager/commands/build.py`:
- Around line 490-492: Move the wheels.get_build_tag call outside the broad
exception handler, or narrow that handler so hook exceptions and invalid hook
output propagate to the caller. Preserve cache-miss handling only for the
intended lookup failures, ensuring expected_tag computation cannot trigger an
unnecessary source build.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 23d637e9-8522-4f9e-aaa7-0ca9ea5e2542

📥 Commits

Reviewing files that changed from the base of the PR and between 6f17876 and c65d608.

📒 Files selected for processing (10)
  • src/fromager/bootstrapper/_cache.py
  • src/fromager/commands/build.py
  • src/fromager/finders.py
  • src/fromager/packagesettings/__init__.py
  • src/fromager/packagesettings/_models.py
  • src/fromager/packagesettings/_settings.py
  • src/fromager/wheels.py
  • tests/test_finders.py
  • tests/test_packagesettings.py
  • tests/test_wheels.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/test_finders.py
  • src/fromager/finders.py
  • src/fromager/packagesettings/_settings.py
  • src/fromager/bootstrapper/_cache.py
  • tests/test_wheels.py
  • src/fromager/wheels.py

Comment thread src/fromager/commands/build.py Outdated
@jlarkin09
jlarkin09 force-pushed the feat/wheel-build-tag-hook-1181 branch from c65d608 to ff96cef Compare July 29, 2026 21:34
Implement the accepted proposal from docs/proposals/wheel-build-tag-hook.md
(issue python-wheel-build#1059, tracking issue python-wheel-build#1181).

Add a `wheels.build_tag_hook` option in global settings that lets downstream
projects append environment-specific suffixes (OS, accelerator, torch ABI)
to wheel build tags via a user-defined callable. The hook receives ctx, req,
version, and wheel_tags and returns suffix segments joined with `_`.

- Add `WheelSettings` model with `build_tag_hook: ImportString` to settings
- Add `get_build_tag()` and `_validate_build_tag_segments()` to wheels.py
- Update `add_extra_metadata_to_wheels()`, bootstrapper cache checks, and
  `_is_wheel_built()` to use computed build tags
- Minimal finder update to match suffixed build tag filenames
- Validate hook output: reject single strings, invalid chars, non-strings
- No behavior change when hook is not configured

Closes: python-wheel-build#1181

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Justin Larkin <jlarkin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Justin Larkin <jlarkin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Justin Larkin <jlarkin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Justin Larkin <jlarkin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Justin Larkin <jlarkin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Justin Larkin <jlarkin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@jlarkin09
jlarkin09 force-pushed the feat/wheel-build-tag-hook-1181 branch from ff96cef to fbc46b5 Compare July 30, 2026 14:08
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.

Implement wheel_build_tag hook for unique wheel file names

2 participants