Turn deprecated --force_python into a no-op
The flag now behaves as if it is always unset. It will be removed entirely in a separate CL. In the meantime, it is still disallowed to select() on the flag.
Work toward #7797.
RELNOTES: None
PiperOrigin-RevId: 302665836
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PythonConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/python/PythonConfiguration.java
index c5e8d93..9acc4cf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PythonConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PythonConfiguration.java
@@ -90,8 +90,7 @@
* Returns the Python version to use.
*
* <p>Specified using either the {@code --python_version} flag and {@code python_version} rule
- * attribute (new API), or the {@code --force_python} flag and {@code default_python_version} rule
- * attribute (old API).
+ * attribute (new API), or the {@code default_python_version} rule attribute (old API).
*/
public PythonVersion getPythonVersion() {
return version;
@@ -135,11 +134,6 @@
@Override
public void reportInvalidOptions(EventHandler reporter, BuildOptions buildOptions) {
PythonOptions opts = buildOptions.get(PythonOptions.class);
- if (opts.forcePython != null && opts.incompatibleRemoveOldPythonVersionApi) {
- reporter.handle(
- Event.error(
- "`--force_python` is disabled by `--incompatible_remove_old_python_version_api`"));
- }
if (opts.incompatiblePy3IsDefault && !opts.incompatibleAllowPythonVersionTransitions) {
reporter.handle(
Event.error(
@@ -168,10 +162,7 @@
return buildTransitiveRunfilesTrees;
}
- /**
- * Returns whether use of {@code --force_python} flag and {@code default_python_version} attribute
- * is allowed.
- */
+ /** Returns whether use of the {@code default_python_version} attribute is allowed. */
public boolean oldPyVersionApiAllowed() {
return oldPyVersionApiAllowed;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PythonOptions.java b/src/main/java/com/google/devtools/build/lib/rules/python/PythonOptions.java
index aca45d8..44b835c4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PythonOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PythonOptions.java
@@ -79,7 +79,7 @@
OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
},
help =
- "If true, disables use of the `--force_python` flag and the `default_python_version` "
+ "If true, disables use of the `default_python_version` "
+ "attribute for `py_binary` and `py_test`. Use the `--python_version` flag and "
+ "`python_version` attribute instead, which have exactly the same meaning. This "
+ "flag also disables `select()`-ing over `--host_force_python`.")
@@ -169,25 +169,17 @@
OptionsParser.getOptionDefinitionByName(PythonOptions.class, "python_version");
/**
- * This field should be either null (unset), {@code PY2}, or {@code PY3}. Other {@code
- * PythonVersion} values do not represent distinct Python versions and are not allowed.
+ * Deprecated machinery for setting the Python version; will be removed soon.
*
- * <p>This flag is not accessible to the user when {@link #incompatibleRemoveOldPythonVersionApi}
- * is true.
- *
- * <p>Native rule logic should call {@link #getPythonVersion} / {@link #setPythonVersion} instead
- * of accessing this option directly. BUILD/.bzl code should {@code select()} on {@code <tools
- * repo>//tools/python:python_version} rather than on this option directly.
+ * <p>Not in GraveyardOptions because we still want to prohibit users from select()ing on it.
*/
@Option(
name = "force_python",
defaultValue = "null",
converter = TargetPythonVersionConverter.class,
- documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
+ documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS, OptionEffectTag.AFFECTS_OUTPUTS},
- help =
- "Deprecated alias for `--python_version`. Disabled by "
- + "`--incompatible_remove_old_python_version_api`.")
+ help = "No-op, will be removed soon.")
public PythonVersion forcePython;
private static final OptionDefinition FORCE_PYTHON_DEFINITION =
@@ -322,14 +314,12 @@
/**
* Returns the Python major version ({@code PY2} or {@code PY3}) that targets should be built for.
*
- * <p>The version is taken as the value of {@code --python_version} if not null, otherwise {@code
- * --force_python} if not null, otherwise {@link #getDefaultPythonVersion}.
+ * <p>The version is taken as the value of {@code --python_version} if not null, otherwise {@link
+ * #getDefaultPythonVersion}.
*/
public PythonVersion getPythonVersion() {
if (pythonVersion != null) {
return pythonVersion;
- } else if (forcePython != null) {
- return forcePython;
} else {
return getDefaultPythonVersion();
}
@@ -343,10 +333,10 @@
* different from the existing one.
*
* <p>Under the old semantics ({@link #incompatibleAllowPythonVersionTransitions} is false),
- * version transitions are not allowed once the version has already been set ({@link #forcePython}
- * or {@link #pythonVersion} is non-null). Due to a historical bug, it is also not allowed to
- * transition the version to the hard-coded default value. Under these constraints, there is only
- * one transition possible, from null to the non-default value, and it is never a no-op.
+ * version transitions are not allowed once the version has already been set ({@link
+ * #pythonVersion} is non-null). Due to a historical bug, it is also not allowed to transition the
+ * version to the hard-coded default value. Under these constraints, there is only one transition
+ * possible, from null to the non-default value, and it is never a no-op.
*
* @throws IllegalArgumentException if {@code version} is not {@code PY2} or {@code PY3}
*/
@@ -355,7 +345,7 @@
if (incompatibleAllowPythonVersionTransitions) {
return !version.equals(getPythonVersion());
} else {
- boolean currentlyUnset = forcePython == null && pythonVersion == null;
+ boolean currentlyUnset = pythonVersion == null;
boolean transitioningToNonDefault = !version.equals(getDefaultPythonVersion());
return currentlyUnset && transitioningToNonDefault;
}
@@ -372,22 +362,11 @@
* <p>If the old semantics are in effect ({@link #incompatibleAllowPythonVersionTransitions} is
* false), after this method is called {@link #canTransitionPythonVersion} will return false.
*
- * <p>To help avoid breaking old-API {@code select()} expressions that check the value of {@code
- * "force_python"}, both the old and new flags are updated even though {@code --python_version}
- * takes precedence over {@code --force_python}.
- *
* @throws IllegalArgumentException if {@code version} is not {@code PY2} or {@code PY3}
*/
public void setPythonVersion(PythonVersion version) {
Preconditions.checkArgument(version.isTargetValue());
this.pythonVersion = version;
- // If the old version API is enabled, update forcePython for consistency. If the old API is
- // disabled, don't update it because 1) no one can read it anyway, and 2) updating it during
- // normalization would cause analysis-time validation of the flag to spuriously fail (it'd think
- // the user set the flag).
- if (!incompatibleRemoveOldPythonVersionApi) {
- this.forcePython = version;
- }
}
@Override
@@ -416,7 +395,7 @@
public FragmentOptions getNormalized() {
// Under the new version semantics, we want to ensure that options with "null" physical default
// values are normalized, to avoid #7808. We don't want to normalize with the old version
- // semantics because that breaks backwards compatibility (--force_python would always be on).
+ // semantics because that breaks backwards compatibility.
PythonOptions newOptions = (PythonOptions) clone();
if (incompatibleAllowPythonVersionTransitions) {
newOptions.setPythonVersion(newOptions.getPythonVersion());
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PyBaseConfiguredTargetTestBase.java b/src/test/java/com/google/devtools/build/lib/rules/python/PyBaseConfiguredTargetTestBase.java
index c7ba4da..d3767f6 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PyBaseConfiguredTargetTestBase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PyBaseConfiguredTargetTestBase.java
@@ -102,7 +102,7 @@
@Test
public void versionIs3IfForcedByFlagUnderOldSemantics() throws Exception {
- // Under the old version semantics, --force_python takes precedence over the rule's own
+ // Under the old version semantics, --python_version takes precedence over the rule's own
// default_python_version attribute, so this test case applies equally well to py_library,
// py_binary, and py_test. Under the new semantics the rule attribute takes precedence, so this
// would only make sense for py_library; see PyLibraryConfiguredTargetTest for the analogous
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PyExecutableConfiguredTargetTestBase.java b/src/test/java/com/google/devtools/build/lib/rules/python/PyExecutableConfiguredTargetTestBase.java
index a5d3092..5cd8e8b 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PyExecutableConfiguredTargetTestBase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PyExecutableConfiguredTargetTestBase.java
@@ -359,18 +359,11 @@
assumesDefaultIsPY2();
scratch.file("pkg/BUILD", ruleDeclWithPyVersionAttr("foo", "PY3"));
- // Test against both flags.
- assertPythonVersionIs_UnderNewConfigs(
+ assertPythonVersionIs_UnderNewConfig(
"//pkg:foo",
PythonVersion.PY3,
- new String[] {
- "--incompatible_allow_python_version_transitions=true",
- "--incompatible_remove_old_python_version_api=false",
- "--force_python=PY2"
- },
- new String[] {
- "--incompatible_allow_python_version_transitions=true", "--python_version=PY2"
- });
+ "--incompatible_allow_python_version_transitions=true",
+ "--python_version=PY2");
}
@Test
@@ -378,18 +371,11 @@
assumesDefaultIsPY2();
scratch.file("pkg/BUILD", ruleDeclWithPyVersionAttr("foo", "PY2"));
- // Test against both flags.
- assertPythonVersionIs_UnderNewConfigs(
+ assertPythonVersionIs_UnderNewConfig(
"//pkg:foo",
PythonVersion.PY2,
- new String[] {
- "--incompatible_allow_python_version_transitions=true",
- "--incompatible_remove_old_python_version_api=false",
- "--force_python=PY3"
- },
- new String[] {
- "--incompatible_allow_python_version_transitions=true", "--python_version=PY3"
- });
+ "--incompatible_allow_python_version_transitions=true",
+ "--python_version=PY3");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PythonConfigurationTest.java b/src/test/java/com/google/devtools/build/lib/rules/python/PythonConfigurationTest.java
index 3632960..998fc0c 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PythonConfigurationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PythonConfigurationTest.java
@@ -38,29 +38,18 @@
@Test
public void invalidTargetPythonValue_NotATargetValue() {
OptionsParsingException expected =
- assertThrows(OptionsParsingException.class, () -> create("--force_python=PY2AND3"));
+ assertThrows(OptionsParsingException.class, () -> create("--python_version=PY2AND3"));
assertThat(expected).hasMessageThat().contains("Not a valid Python major version");
}
@Test
public void invalidTargetPythonValue_UnknownValue() {
OptionsParsingException expected =
- assertThrows(
- OptionsParsingException.class,
- () -> create("--force_python=BEETLEJUICE"));
+ assertThrows(OptionsParsingException.class, () -> create("--python_version=BEETLEJUICE"));
assertThat(expected).hasMessageThat().contains("Not a valid Python major version");
}
@Test
- public void oldVersionFlagGatedByIncompatibleFlag() throws Exception {
- create("--incompatible_remove_old_python_version_api=false", "--force_python=PY2");
- checkError(
- "`--force_python` is disabled by `--incompatible_remove_old_python_version_api`",
- "--incompatible_remove_old_python_version_api=true",
- "--force_python=PY2");
- }
-
- @Test
public void py3IsDefaultFlagRequiresNewSemanticsFlag() throws Exception {
checkError(
"cannot enable `--incompatible_py3_is_default` without also enabling "
@@ -102,28 +91,6 @@
}
@Test
- public void getPythonVersion_NewFlagTakesPrecedence() throws Exception {
- assumesDefaultIsPY2();
- // --force_python is superseded by --python_version.
- PythonOptions opts =
- parsePythonOptions(
- "--incompatible_remove_old_python_version_api=false",
- "--force_python=PY2",
- "--python_version=PY3");
- assertThat(opts.getPythonVersion()).isEqualTo(PythonVersion.PY3);
- }
-
- @Test
- public void getPythonVersion_FallBackOnOldFlag() throws Exception {
- assumesDefaultIsPY2();
- // --force_python is used because --python_version is absent.
- PythonOptions opts =
- parsePythonOptions(
- "--incompatible_remove_old_python_version_api=false", "--force_python=PY3");
- assertThat(opts.getPythonVersion()).isEqualTo(PythonVersion.PY3);
- }
-
- @Test
public void canTransitionPythonVersion_OldSemantics_Yes() throws Exception {
assumesDefaultIsPY2();
PythonOptions opts =
@@ -134,16 +101,10 @@
@Test
public void canTransitionPythonVersion_OldSemantics_NoBecauseAlreadySet() throws Exception {
assumesDefaultIsPY2();
- PythonOptions optsWithOldFlag =
- parsePythonOptions(
- "--incompatible_allow_python_version_transitions=false",
- "--incompatible_remove_old_python_version_api=false",
- "--force_python=PY2");
- PythonOptions optsWithNewFlag =
+ PythonOptions opts =
parsePythonOptions(
"--incompatible_allow_python_version_transitions=false", "--python_version=PY2");
- assertThat(optsWithOldFlag.canTransitionPythonVersion(PythonVersion.PY3)).isFalse();
- assertThat(optsWithNewFlag.canTransitionPythonVersion(PythonVersion.PY3)).isFalse();
+ assertThat(opts.canTransitionPythonVersion(PythonVersion.PY3)).isFalse();
}
@Test
@@ -168,23 +129,7 @@
PythonOptions opts =
parsePythonOptions(
"--incompatible_allow_python_version_transitions=true",
- // Set --force_python too, or else we fall into the "make --force_python consistent"
- // case.
"--incompatible_remove_old_python_version_api=false",
- "--force_python=PY3",
- "--python_version=PY3");
- assertThat(opts.canTransitionPythonVersion(PythonVersion.PY3)).isFalse();
- }
-
- @Test
- public void canTransitionPythonVersion_NewApi_NoEvenWhenForcePythonDisagrees() throws Exception {
- PythonOptions opts =
- parsePythonOptions(
- "--incompatible_allow_python_version_transitions=true",
- "--incompatible_remove_old_python_version_api=false",
- // Test that even though --force_python's value isn't in sync, we don't transition
- // because getPythonVersion() would be unaffected by the transition.
- "--force_python=PY2",
"--python_version=PY3");
assertThat(opts.canTransitionPythonVersion(PythonVersion.PY3)).isFalse();
}
@@ -194,10 +139,8 @@
PythonOptions opts =
parsePythonOptions(
"--incompatible_remove_old_python_version_api=false",
- "--force_python=PY2",
"--python_version=PY2");
opts.setPythonVersion(PythonVersion.PY3);
- assertThat(opts.forcePython).isEqualTo(PythonVersion.PY3);
assertThat(opts.pythonVersion).isEqualTo(PythonVersion.PY3);
}
@@ -207,7 +150,6 @@
parsePythonOptions(
"--incompatible_remove_old_python_version_api=true", "--python_version=PY2");
opts.setPythonVersion(PythonVersion.PY3);
- assertThat(opts.forcePython).isNull();
assertThat(opts.pythonVersion).isEqualTo(PythonVersion.PY3);
}
@@ -235,11 +177,6 @@
@Test
public void getHost_AppliesHostForcePython() throws Exception {
assumesDefaultIsPY2();
- PythonOptions optsWithForcePythonFlag =
- parsePythonOptions(
- "--incompatible_remove_old_python_version_api=false",
- "--force_python=PY2",
- "--host_force_python=PY3");
PythonOptions optsWithPythonVersionFlag =
parsePythonOptions("--python_version=PY2", "--host_force_python=PY3");
PythonOptions optsWithPy3IsDefaultFlag =
@@ -250,11 +187,9 @@
// It's more interesting to set the incompatible flag true and force host to PY2, than
// it is to set the flag false and force host to PY3.
"--host_force_python=PY2");
- PythonOptions hostOptsWithForcePythonFlag = (PythonOptions) optsWithForcePythonFlag.getHost();
PythonOptions hostOptsWithPythonVersionFlag =
(PythonOptions) optsWithPythonVersionFlag.getHost();
PythonOptions hostOptsWithPy3IsDefaultFlag = (PythonOptions) optsWithPy3IsDefaultFlag.getHost();
- assertThat(hostOptsWithForcePythonFlag.getPythonVersion()).isEqualTo(PythonVersion.PY3);
assertThat(hostOptsWithPythonVersionFlag.getPythonVersion()).isEqualTo(PythonVersion.PY3);
assertThat(hostOptsWithPy3IsDefaultFlag.getPythonVersion()).isEqualTo(PythonVersion.PY2);
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PythonVersionSelectTest.java b/src/test/java/com/google/devtools/build/lib/rules/python/PythonVersionSelectTest.java
index 413b483..6b39058 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PythonVersionSelectTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PythonVersionSelectTest.java
@@ -72,6 +72,8 @@
public void canSelectOnForcePythonFlagsUnderOldApi() throws Exception {
// For backwards compatibility purposes, select()-ing on --force_python and --host_force_python
// is allowed while the old API is still enabled.
+ // TODO(brandjon): Although --force_python is a no-op, this test is still present because the
+ // behavior belongs to the remove-old-api flag. Delete the test when we no-op that flag too.
useConfiguration("--incompatible_remove_old_python_version_api=false");
scratch.file("fp/BUILD", makeFooThatSelectsOnFlag("force_python", "PY2"));
scratch.file("hfp/BUILD", makeFooThatSelectsOnFlag("host_force_python", "PY2"));
@@ -119,7 +121,7 @@
" }),",
")");
- // Neither --python_version nor --force_python, use default value.
+ // No --python_version, use default value.
doTestSelectOnPythonVersionTarget(py2, "--incompatible_py3_is_default=false");
doTestSelectOnPythonVersionTarget(
py3,
@@ -128,17 +130,9 @@
// enabled before we're allowed to set the default to PY3.
"--incompatible_allow_python_version_transitions=true");
- // No --python_version, trust --force_python.
- doTestSelectOnPythonVersionTarget(py2, "--force_python=PY2");
- doTestSelectOnPythonVersionTarget(py3, "--force_python=PY3");
-
- // --python_version overrides --force_python.
+ // --python_version is given, use it.
doTestSelectOnPythonVersionTarget(py2, "--python_version=PY2");
- doTestSelectOnPythonVersionTarget(py2, "--python_version=PY2", "--force_python=PY2");
- doTestSelectOnPythonVersionTarget(py2, "--python_version=PY2", "--force_python=PY3");
doTestSelectOnPythonVersionTarget(py3, "--python_version=PY3");
- doTestSelectOnPythonVersionTarget(py3, "--python_version=PY3", "--force_python=PY2");
- doTestSelectOnPythonVersionTarget(py3, "--python_version=PY3", "--force_python=PY3");
}
private void doTestSelectOnPythonVersionTarget(Artifact expected, String... flags)