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

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

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1ce4e72b-5ec8-40d4-9421-2fbec00a59ce

📥 Commits

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

📒 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 (9)
  • src/fromager/packagesettings/init.py
  • src/fromager/packagesettings/_models.py
  • src/fromager/packagesettings/_settings.py
  • src/fromager/bootstrapper/_cache.py
  • tests/test_finders.py
  • src/fromager/finders.py
  • tests/test_wheels.py
  • src/fromager/wheels.py
  • src/fromager/commands/build.py

📝 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 new configurable wheel build-tag hook feature.
Description check ✅ Passed The description matches the PR changes and scope around wheel build-tag hooks.
Linked Issues check ✅ Passed The changes appear to satisfy #1181 by adding settings, validation, suffix building, and cache/finder updates.
Out of Scope Changes check ✅ Passed The diff stays focused on the wheel build-tag hook feature and supporting tests/settings.

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
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>
@jlarkin09
jlarkin09 force-pushed the feat/wheel-build-tag-hook-1181 branch from 5b89a26 to 6445684 Compare July 25, 2026 02:17
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

1 participant