Skip to content

Commit d1bbf4b

Browse files
rickeylevcopybara-github
authored andcommitted
Add --incompatible_python_disable_py2, which fails if Python 2 is specified.
When true, using Python 2 only attribute values will cause an error. More specifically, using `python_version=PY2`, `srcs_version=PY2` or `srcs_version=PY2ONLY` with `py_binary`, `py_test`, `py_library`, `py_runtime`, or `py_runtime_pair` will result in an error. Work towards #15684 PiperOrigin-RevId: 501959931 Change-Id: I7bc089a2f7b46f2538e4a92d8753c788193a71d5
1 parent 24dbe0d commit d1bbf4b

File tree

5 files changed

+62
-8
lines changed

5 files changed

+62
-8
lines changed

src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
4040
import com.google.devtools.build.lib.cmdline.LabelConstants;
4141
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
42+
import com.google.devtools.build.lib.packages.Type;
4243
import com.google.devtools.build.lib.rules.cpp.CcInfo;
4344
import com.google.devtools.build.lib.rules.python.PyCcLinkParamsProvider;
4445
import com.google.devtools.build.lib.rules.python.PyCommon;
@@ -77,6 +78,19 @@ public String getSrcsVersionDocURL() {
7778

7879
@Override
7980
public void validate(RuleContext ruleContext, PyCommon common) {
81+
PythonConfiguration config = ruleContext.getFragment(PythonConfiguration.class);
82+
if (config.getDisablePy2()) {
83+
var attrs = ruleContext.attributes();
84+
if (config.getDefaultPythonVersion().equals(PythonVersion.PY2)
85+
|| attrs.getOrDefault("python_version", Type.STRING, "UNSET").equals("PY2")
86+
|| attrs.getOrDefault("srcs_version", Type.STRING, "UNSET").equals("PY2")
87+
|| attrs.getOrDefault("srcs_version", Type.STRING, "UNSET").equals("PY2ONLY")) {
88+
ruleContext.ruleError(
89+
"Using Python 2 is not supported and disabled; see "
90+
+ "https://github.com/bazelbuild/bazel/issues/15684");
91+
return;
92+
}
93+
}
8094
}
8195

8296
@Override
@@ -116,18 +130,18 @@ public List<String> getImports(RuleContext ruleContext) {
116130
PathFragment packageFragment = ruleContext.getLabel().getPackageIdentifier().getRunfilesPath();
117131
// Python scripts start with x.runfiles/ as the module space, so everything must be manually
118132
// adjusted to be relative to the workspace name.
119-
packageFragment = PathFragment.create(ruleContext.getWorkspaceName())
120-
.getRelative(packageFragment);
133+
packageFragment =
134+
PathFragment.create(ruleContext.getWorkspaceName()).getRelative(packageFragment);
121135
for (String importsAttr : ruleContext.getExpander().list("imports")) {
122136
if (importsAttr.startsWith("/")) {
123-
ruleContext.attributeWarning("imports",
124-
"ignoring invalid absolute path '" + importsAttr + "'");
137+
ruleContext.attributeWarning(
138+
"imports", "ignoring invalid absolute path '" + importsAttr + "'");
125139
continue;
126140
}
127141
PathFragment importsPath = packageFragment.getRelative(importsAttr);
128142
if (importsPath.containsUplevelReferences()) {
129-
ruleContext.attributeError("imports",
130-
"Path " + importsAttr + " references a path above the execution root");
143+
ruleContext.attributeError(
144+
"imports", "Path " + importsAttr + " references a path above the execution root");
131145
}
132146
result.add(importsPath.getPathString());
133147
}
@@ -279,7 +293,7 @@ public void createExecutable(
279293
// unix. See also https://github.com/bazelbuild/bazel/issues/7947#issuecomment-491385802.
280294
pythonBinary,
281295
executable,
282-
/*useZipFile=*/ buildPythonZip);
296+
/* useZipFile= */ buildPythonZip);
283297
}
284298
}
285299

@@ -468,7 +482,7 @@ private static String getPythonBinary(
468482
pythonBinary =
469483
workspaceName.getRelative(provider.getInterpreter().getRunfilesPath()).getPathString();
470484
}
471-
} else {
485+
} else {
472486
// make use of the Python interpreter in an absolute path
473487
pythonBinary = bazelConfig.getPythonPath();
474488
}

src/main/java/com/google/devtools/build/lib/rules/python/PythonConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class PythonConfiguration extends Fragment implements StarlarkValue {
5252
private final boolean useToolchains;
5353

5454
private final boolean defaultToExplicitInitPy;
55+
private final boolean disablePy2;
5556

5657
public PythonConfiguration(BuildOptions buildOptions) {
5758
PythonOptions pythonOptions = buildOptions.get(PythonOptions.class);
@@ -64,6 +65,7 @@ public PythonConfiguration(BuildOptions buildOptions) {
6465
this.py2OutputsAreSuffixed = pythonOptions.incompatiblePy2OutputsAreSuffixed;
6566
this.useToolchains = pythonOptions.incompatibleUsePythonToolchains;
6667
this.defaultToExplicitInitPy = pythonOptions.incompatibleDefaultToExplicitInitPy;
68+
this.disablePy2 = pythonOptions.disablePy2;
6769
}
6870

6971
@Override
@@ -172,4 +174,12 @@ public boolean useToolchains() {
172174
public boolean defaultToExplicitInitPy() {
173175
return defaultToExplicitInitPy;
174176
}
177+
178+
@StarlarkMethod(
179+
name = "disable_py2",
180+
structField = true,
181+
doc = "The value of the --incompatible_python_disable_py2 flag.")
182+
public boolean getDisablePy2() {
183+
return disablePy2;
184+
}
175185
}

src/main/java/com/google/devtools/build/lib/rules/python/PythonOptions.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ public String getTypeDescription() {
119119
+ "`--incompatible_py2_outputs_are_suffixed`.")
120120
public boolean incompatiblePy3IsDefault;
121121

122+
@Option(
123+
name = "incompatible_python_disable_py2",
124+
defaultValue = "false",
125+
documentationCategory = OptionDocumentationCategory.INPUT_STRICTNESS,
126+
effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS},
127+
metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE},
128+
help =
129+
"If true, using Python 2 settings will cause an error. This includes "
130+
+ "python_version=PY2, srcs_version=PY2, and srcs_version=PY2ONLY. See "
131+
+ "https://github.com/bazelbuild/bazel/issues/15684 for more information.")
132+
public boolean disablePy2;
133+
122134
@Option(
123135
name = "incompatible_py2_outputs_are_suffixed",
124136
defaultValue = "true",
@@ -342,6 +354,7 @@ public FragmentOptions getExec() {
342354
hostPythonOptions.incompatibleDefaultToExplicitInitPy = incompatibleDefaultToExplicitInitPy;
343355
hostPythonOptions.incompatibleDisallowLegacyPyProvider = incompatibleDisallowLegacyPyProvider;
344356
hostPythonOptions.incompatibleRemoveOldPythonVersionApi = incompatibleRemoveOldPythonVersionApi;
357+
hostPythonOptions.disablePy2 = disablePy2;
345358

346359
// Save host options in case of a further exec->host transition.
347360
hostPythonOptions.hostForcePython = hostForcePython;

src/main/starlark/builtins_bzl/common/python/py_runtime_rule.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ def _py_runtime_impl(ctx):
6666
else:
6767
python_version = ctx.fragments.py.default_python_version
6868

69+
if ctx.fragments.py.disable_py2 and python_version == "PY2":
70+
fail("Using Python 2 is not supported and disabled; see " +
71+
"https://github.com/bazelbuild/bazel/issues/15684")
72+
6973
return [
7074
_PyRuntimeInfo(
7175
interpreter_path = interpreter_path or None,

tools/python/toolchain.bzl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,23 @@ def _py_runtime_pair_impl(ctx):
3434
else:
3535
py3_runtime = None
3636

37+
if _is_py2_disabled(ctx) and py2_runtime != None:
38+
fail("Using Python 2 is not supported and disabled; see " +
39+
"https://github.com/bazelbuild/bazel/issues/15684")
40+
3741
return [platform_common.ToolchainInfo(
3842
py2_runtime = py2_runtime,
3943
py3_runtime = py3_runtime,
4044
)]
4145

46+
def _is_py2_disabled(ctx):
47+
# In Google, this file isn't bundled with Bazel, so we have to conditionally
48+
# check for this flag.
49+
# TODO: Remove this once a build with the flag is released in Google
50+
if not hasattr(ctx.fragments.py, "disable_py"):
51+
return False
52+
return ctx.fragments.py.disable_py2
53+
4254
py_runtime_pair = rule(
4355
implementation = _py_runtime_pair_impl,
4456
attrs = {
@@ -61,6 +73,7 @@ The runtime to use for Python 3 targets. Must have `python_version` set to
6173
""",
6274
),
6375
},
76+
fragments = ["py"],
6477
doc = """\
6578
A toolchain rule for Python.
6679

0 commit comments

Comments
 (0)