-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Description
Flag: --incompatible_allow_python_version_transitions
Available since: 0.23
Will be flipped in: either 0.24 or 0.25, depending on migration progress
Tracking issue: #6583
Design doc
Corresponding syntactic change: #7308
Motivation
The Python mode behaved in a confusing and error-prone way, and didn't support important use cases like a Python 3 binary depending on a Python 2 one in its data attribute.
See the design doc for more details.
Note: This incompatible change affects the mechanism that Bazel uses to decide whether a target should be built for Python 2 or 3. However, due to #4815, even when a target is built for Python 3 it may still execute under a Python 2 interpreter. See the workaround using py_runtime / --python_top in #4815 (comment).
Change
This makes the Python version have only two possible states: PY2 and PY3. The version can change whenever an executable Python rule (py_binary or py_test) is encountered, even if the version was previously set by another target or by a top-level flag.
In addition, srcs_version validation is done at the level of the executable target, rather than in each py_library. This makes it so you can do bazel build //... without getting errors from PY2-only or PY3-only libraries.
This change does not remove any syntax. See --incompatible_remove_old_python_version_api for that.
Note: This change does not affect targets built in the host configuration, such as targets in genrule's tools attribute, or user-defined rules that set cfg = host on an attribute. This is a consequence of technical limitations on the host configuration to be addressed in future work. In the meantime, you can set a Python version to use globally for all host-configured targets by setting --host_force_python=[PY2 | PY3].
Migration
If you were relying on --force_python to control your Python mode, that won't work anymore since py_binary will set its own mode. Use the python_version attribute (formerly default_python_version) on py_binary instead.
Using multiple Python versions in the same build can lead to action conflicts if you test the python version by select()-ing on "force_python". To avoid this, you should instead select on @bazel_tools//tools/python:python_version. See here. You can ensure that your build doesn't select on "force_python" by enabling --incompatible_remove_old_python_version_api.
Another type of action conflict can arise due to #7655 when a cc_library is data-depended on by a py_binary. This kind of conflict can be avoided by enabling --incompatible_remove_old_python_version_api. If you're not able to migrate your build to enable that flag yet, you can also avoid this particular conflict by explicitly passing a value for the --force_python flag that matches the value passed for --python_version (or the default value if --python_version is not passed).
If there's a srcs_version conflict in your build, you will no longer see an error at the py_library that introduces the conflict. Instead you'll see it in the py_binary or py_test that transitively depends on the library. The error message will not identify which library introduced the version constraint. To find it, you can run the aspect @bazel_tools//tools/python:srcs_version.bzl%find_requirements as follows:
bazel build <your target> \
--aspects=@bazel_tools//tools/python:srcs_version.bzl%find_requirements \
--output_groups=pyversioninfo
This will build a [...]-pyversioninfo.txt file explaining what dependency requires what Python version. You can run it directly on the py_binary or py_test that failed due to a version conflict.