-
Notifications
You must be signed in to change notification settings - Fork 543
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(config_settings): allow matching minor version of python_version flag #1555
Conversation
…sion` flag Currently user has to specify a full (x.y.z) version of Python when setting the `python_version` flag. When they upgrade `rules_python` or change `MINOR_MAPPING` in some other way, user has to update the flag's value to keep it in sync with `MINOR_MAPPING`. This patch allows `python_version` flag to accept minor (x.y) versions and resolves them to the corresponding full versions using `MINOR_MAPPING`.
|
||
minor_versions = list(minor_mapping.keys()) | ||
allowed_flag_values = python_versions + minor_versions | ||
|
||
string_flag( | ||
name = "python_version", | ||
build_setting_default = python_versions[0], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using build_setting_default = python_versions[0]
here looks like a minor bug, BTW.
It enables a config setting, and if user manages to configure a toolchain that matches this full version, this toolchain will be selected by default, instead of the one marked by the is_default
attr in python.toolchain(...)
.
I think a better approach would be to have something like build_setting_default = "default"
and values = ["default"] + allowed_flag_values
passed to the string_flag(...)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"default" is a bit overloaded here.
What python.toolchain's is_default=True
affects is what //conditions:default
points to, essentially. If that is hit, it basically means either the version-unaware rules are being used, or there is no matching version-aware toolchain configured.
The build_setting_default
value here affects what the version-aware rules use if there isn't something overriding the value (i.e. command line flag, or the target-specific override).
I agree that it would be best if the version set with is_default=True
in the module config should match what this flag defaults to. I think this is possible? By putting the value in a generated repo and loading it here, similar to how rules_python_internal works. But lets have that as part of a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment to note this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please explain how this would be used? What implications for users? I see all of the new targets are public
, do they have to be?
Currently users can switch python toolchains by passing Allowed values for this flag are rules_python/examples/multi_python_versions/MODULE.bazel Lines 13 to 16 in a9032d2
rules_python/examples/multi_python_versions/MODULE.bazel Lines 38 to 42 in a9032d2
The latter pip.parse call leads to generating a select for every wheel:Lines 188 to 198 in a9032d2
To land in a 3.9 branch in this select, you need to specify 3.9.18 as the flag's value, and when MINOR_MAPPING inevitably get updated, pip.parse call will renter the template with a different full_python_version , and after that moment passing --@rules_python//python/config_settings:python_version=3.9.18 will lead to selecting the default toolchain (that might not even be 3.9), leading to confusion.
This PR allows users to specify
Flag starts to accept a new set of values in addition to previously accepted ones.
I'm not expert here, but I got an error when I made |
Thanks for the explanation, this is the first time I've heard you can switch the registered python like this and this is really interesting. And the Hyrum's law mention make sense in this case, just wanted to understand the Y in the XY. If I understand correctly, what you are after is being able to select the version using |
Thanks for this PR. This topic has come up in the back of my mind a few times, but I haven't had time to think on it. I, too, want to allow specifying and matching the version to work with both minor and patch levels specified. Libraries matching every patch version doesn't scale, for example.
Yes! This is exactly the intent of these flags 😄. If you have remote execution, you can even take it a step further by putting a transition around the targets to force them to particular platforms or versions and thus test everything in a single build invocation. It's pretty nice when it's all put together. |
|
||
minor_versions = list(minor_mapping.keys()) | ||
allowed_flag_values = python_versions + minor_versions | ||
|
||
string_flag( | ||
name = "python_version", | ||
build_setting_default = python_versions[0], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"default" is a bit overloaded here.
What python.toolchain's is_default=True
affects is what //conditions:default
points to, essentially. If that is hit, it basically means either the version-unaware rules are being used, or there is no matching version-aware toolchain configured.
The build_setting_default
value here affects what the version-aware rules use if there isn't something overriding the value (i.e. command line flag, or the target-specific override).
I agree that it would be best if the version set with is_default=True
in the module config should match what this flag defaults to. I think this is possible? By putting the value in a generated repo and loading it here, similar to how rules_python_internal works. But lets have that as part of a separate PR.
@dizzy57, gentle ping. Is this something you would like to get merged? Having a config setting for Python |
@aignas Thanks for the ping, I plan to get back to this diff next week |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some time, so implemented the missing parts
|
||
minor_versions = list(minor_mapping.keys()) | ||
allowed_flag_values = python_versions + minor_versions | ||
|
||
string_flag( | ||
name = "python_version", | ||
build_setting_default = python_versions[0], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment to note this
python_version
flag
I modified this a bit from the original implementation, but I think the intent is the same. The flag value still requires a micro-level version (3.10.1), but an additional config setting is exposed to match a minor-version (3.10) against any of the (known) micro versions. This allows omitting the micro-version is most cases and switching between e.g.
Instead of having to enumerate all the 3.8.x values explicitly, or having to map the minor version back to the full version (as we do in the pip build file generation code). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a few comments on implementation since the merge queue failed.
With this PR we can deterministically parse the METADATA and generate a `BUILD.bazel` file using the config settings introduced in #1555. Let's imagine we had a `requirements.txt` file that used only wheels, we could use the host interpreter to parse the wheel metadata for all the target platforms and use the version aware toolchain at runtime. This potentially unlocks more clever layouts of the `bzlmod` hub repos explored in #1625 where we could have a single `whl_library` instance for all versions within a single hub repo. Work towards #1643.
This is inspired by how rules_go is registering their toolchains. Their toolchains have multiple `target_settings` values. This allows for a simpler passing of `X.Y` version to the `py_binary` and `py_test` rules and does not strictly require us to provide the APIs that pass the full python version value as the closure. This is only possible because #1555 introduced working aliases and now we can also have this. Summary: - refactor: move the toolchain_def to starlark as opposed to templating - refactor: move the version setting as well - feat: support matching on X.Y versions - feat: X.Y.Z will match if X.Y is used as python_version flag and the MINOR_MAPPING has `"X.Y": "X.Y.Z"`. - test: add tests checking the generated config settings. - doc: add an example of how we could use the transition files directly See https://github.com/bazelbuild/rules_go/blob/master/go/private/go_toolchain.bzl#L181 --------- Co-authored-by: Richard Levasseur <richardlev@gmail.com>
Currently a user has to specify a full (x.y.z) version of Python when setting the
//python/config_settings:python_version
flag. When they upgraderules_python
or changeMINOR_MAPPING
in some other way, user has to update the flag's value to keep it in sync withMINOR_MAPPING
.This adds micro-version agnostic config settings to allow matching the minor version.
For example e.g.
//python/config_settings:is_python_3.8
will match any of3.8.1, 3.8.2, ...' (or whatever other versions are listed in
TOOL_VERSIONS`)