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.
Flag:
--incompatible_allow_python_version_transitionsAvailable 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
dataattribute.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_topin #4815 (comment).Change
This makes the Python version have only two possible states:
PY2andPY3. The version can change whenever an executable Python rule (py_binaryorpy_test) is encountered, even if the version was previously set by another target or by a top-level flag.In addition,
srcs_versionvalidation is done at the level of the executable target, rather than in eachpy_library. This makes it so you can dobazel build //...without getting errors from PY2-only or PY3-only libraries.This change does not remove any syntax. See
--incompatible_remove_old_python_version_apifor that.Note: This change does not affect targets built in the
hostconfiguration, such as targets ingenrule'stoolsattribute, or user-defined rules that setcfg = hoston 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_pythonto control your Python mode, that won't work anymore sincepy_binarywill set its own mode. Use thepython_versionattribute (formerlydefault_python_version) onpy_binaryinstead.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_libraryis data-depended on by apy_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_pythonflag that matches the value passed for--python_version(or the default value if--python_versionis not passed).If there's a
srcs_versionconflict in your build, you will no longer see an error at thepy_librarythat introduces the conflict. Instead you'll see it in thepy_binaryorpy_testthat 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_requirementsas follows:This will build a
[...]-pyversioninfo.txtfile explaining what dependency requires what Python version. You can run it directly on thepy_binaryorpy_testthat failed due to a version conflict.