Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bzlmod): Implementing wheel annotations via whl_mods #1278

Merged
merged 7 commits into from
Jul 10, 2023

Conversation

chrislovecnm
Copy link
Collaborator

@chrislovecnm chrislovecnm commented Jun 19, 2023

This commit implements a bzlmod extension that allows users to create "annotations" for wheel builds. The wheel_builder.py accepts a JSON file via a parameter called annotations; this extension creates those JSON files. The pip extension accepts a Label -> String dict argument of the JSON files.

This feature is renamed to whl_mods because the JSON files are handled differently
and the name "annotations" is uninformative. This modifies the creation of the BUILD
files and their content, and is much more than just adding some notes about a whl.

The whl_mod extension wheel names and the wheel names in pip must match.

Closes: #1213

@chrislovecnm chrislovecnm requested a review from rickeylev as a code owner June 19, 2023 15:29
@chrislovecnm chrislovecnm force-pushed the wheel-mod-extension branch from a7c626f to 883f866 Compare June 19, 2023 15:35
This commit implements a bzlmod extension that allows users
to create "annotations" for wheel builds.  The wheel_builder.py
accepts a JSON file via a parameter called annotations, and
this extension creates those JSON files. The pip extension accepts
a Label -> String dict argument of said JSON files.

We renamed this to whl_mods because we are handling the JSON files
a bit differently, and IMO annotations is a bit confusing.  We
are providing modifications to the creation of the wheel build
file and other components that impact the wheel build.
This commit implements a bzlmod extension that allows users
to create "annotations" for wheel builds.  The wheel_builder.py
accepts a JSON file via a parameter called annotations, and
this extension creates those JSON files. The pip extension accepts
a Label -> String dict argument of said JSON files.

We renamed this to whl_mods because we are handling the JSON files
a bit differently, and IMO annotations is a bit confusing.  We
are providing modifications to the creation of the wheel build
file and other components that impact the wheel build.
@chrislovecnm chrislovecnm force-pushed the wheel-mod-extension branch from 8264b25 to 8fcfb1d Compare June 19, 2023 18:28
@chrislovecnm chrislovecnm force-pushed the wheel-mod-extension branch 4 times, most recently from 76d5d6b to c2dab50 Compare June 19, 2023 18:53
examples/bzlmod/MODULE.bazel Show resolved Hide resolved
examples/bzlmod/MODULE.bazel Show resolved Hide resolved
examples/bzlmod/pip_repository_annotations_test.py Outdated Show resolved Hide resolved
examples/bzlmod/pip_repository_annotations_test.py Outdated Show resolved Hide resolved
examples/bzlmod/requirements.in Show resolved Hide resolved
python/extensions/whl_mods.bzl Outdated Show resolved Hide resolved
@chrislovecnm chrislovecnm force-pushed the wheel-mod-extension branch from c2dab50 to c5cc712 Compare June 20, 2023 17:32
@chrislovecnm chrislovecnm force-pushed the wheel-mod-extension branch from c5cc712 to 4a7b954 Compare June 20, 2023 17:34
Copy link
Collaborator

@rickeylev rickeylev left a comment

Choose a reason for hiding this comment

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

I'm still kinda meh about using an extension to do this, but this does provide a relatively straight forward way to port a workspace build to bzlmod, so that's a decent win.

Any thought to "auto registering" the modifications?
i.e. by doing this:

pip = use_extension(...)
pip.parse(
  hub_name = "pip", ...
)
pip.whl_mod(
  pip_hub = "pip"
  whl_name = "requests,
)

The "requests" wheel will automatically get modified? No need to manually pass the whl_modifications= arg.

Under the hood, all we need to do is generate e.g. hub_name = pip_name + "_mods"

python/extensions/pip.bzl Outdated Show resolved Hide resolved
python/extensions/pip.bzl Outdated Show resolved Hide resolved
python/extensions/pip.bzl Outdated Show resolved Hide resolved
Comment on lines 451 to 459
This tag class is used to create a pip hub and all of the spokes that are part of that hub.
This tag class reuses the pip attributes that are found in
@rules_python//python/pip_install:pip_repository.bzl
Copy link
Collaborator

Choose a reason for hiding this comment

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

The hub and spoke part isn't very relevant to users (they can't control it, nor do they really see it. The available attributes are self-documenting in the attrs structure, plus we don't support all the same attributes (e.g incompatible_generate_aliases), so pointing users to that is a bit misleading.

Suggested change
This tag class is used to create a pip hub and all of the spokes that are part of that hub.
This tag class reuses the pip attributes that are found in
@rules_python//python/pip_install:pip_repository.bzl
This tag class resolves requirements.txt into dependencies usable by Bazel.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The attributes are not self-documenting because we cannot use stardoc to generate the docs for extensions yet. We have an issue open. As a new user, digging through the code to find the docs is a pain. Do you want me to link the docs for pip or leave them as is?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think referring to the pip repo attrs is ok, but saying/implying it reuses them or supports all of them isn't (it just isn't accurate/true). i.e. "most of the pip attrs are supported" but not "all the pip attrs are supported"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I understand. I will figure out how to document it better.

python/extensions/pip.bzl Outdated Show resolved Hide resolved
python/extensions/pip.bzl Outdated Show resolved Hide resolved
# to create the different JSON files.
for whl_name, mods in whl_maps.items():
build_content = mods.additive_build_content
if mods.additive_build_content_file != None and mods.additive_build_content != "":
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think string attributes default to None? So the second expression will always be true.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

mods.additive_build_content_file is a label. Please explain more. I wish we had unit tests for this darn stuff.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, I meant the additive_build_content != "" part of the expression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See https://bazel.build/rules/lib/toplevel/attr#string. It defaults to an empty string if I am reading the docs correctly.

python/extensions/pip.bzl Outdated Show resolved Hide resolved
python/extensions/pip.bzl Show resolved Hide resolved
@chrislovecnm
Copy link
Collaborator Author

chrislovecnm commented Jun 22, 2023

Any thought to "auto registering" the modifications?

@rickeylev I have thought about it, but we have a use case that I could see could cause us a problem.

I'm curious about what you think. Here is my use case.

We have a foo wheel that differs between Python 3.10 and 3.11, and I need the BUILD files to differ between Python 3.10 and 3.11. If we turn on auto registration, we would need to be able to turn it off as well because I would need to use different hub_names for 3.10 vs. 3.11.

So that would be more code to maintain. Also, it may make it more difficult to debug this because I cannot, as a user, easily change the label.

We could autoregister by a hub_name. Create a whl_mods_hub_name attribute, and then autoregister off of that.

As a user with tricky stuff like this, I like fine-grain control; for instance, I can remove an element from a dict rather than modify the entire whl_mod.

I think the number of people that use this is low, so I would rather have less code and less "magic" happening in the background. We need to document it well.

@chrislovecnm chrislovecnm force-pushed the wheel-mod-extension branch from 07dd164 to 159e4ae Compare June 22, 2023 14:45
@chrislovecnm
Copy link
Collaborator Author

@rickeylev, if when we merge, if the repo is not set up to do a squash on the commits; I need to open another PR on a different branch. Somehow my commits got unmanageable, and doing a rebase is driving me up the wall.

@rickeylev
Copy link
Collaborator

re: squash on commits: squash on commits is enabled. The PR description and title become the commit message.

re: whl mods varying by python version: We could just have python_versions attribute of the whl_mod call that says what versions it applies to.

But, all this said, auto-registration is a nice to have, not a requirement. I'm kinda meh about using an extension for this already, and like the idea of having pip.parse have an arg to specify modifications (as we have now). This lets users create the config themselves if they want, and we can always allow specifying a bzl file, patch file, or w/e in the future to handle some of the other ideas posted in the issue.

Copy link
Collaborator

@rickeylev rickeylev left a comment

Choose a reason for hiding this comment

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

The core impl here is fine, so I'm going to give approval before I head out on vacation.

@chrislovecnm chrislovecnm added this pull request to the merge queue Jul 10, 2023
Merged via the queue into bazelbuild:main with commit 42b72db Jul 10, 2023
@groodt
Copy link
Collaborator

groodt commented Jul 13, 2023

At Canva, we just provide an optional patches argument, which is semantically similar to the patches in http_file and other built-ins. We apply the patches to the unpacked wheels. I think this approach has benefits over providing a bespoke and less flexible implementation with similar behaviour.

We can look into upstreaming our implementation and deprecating annotations and whl_mods if you are interested?

It looks quite clumsy having to build a DSL that supports a weaker and less flexible form of patching. You've got provide arguments, teach people about new functionality, serialize data that represents the transformations to apply that are then deserialized and applied later. With patches, it would look similar I believe, but it wouldn't require a custom DSL or logic, we would just leverage rctx.patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support annotations in bzlmod's pip extension
3 participants