Introduce PyInfo to replace the legacy "py" struct provider
This CL adds the PyInfo data type and registers it with a bootstrap. A follow-up CL will make the Python rules actually produce and consume this provider.
The new provider's API exactly mirrors the current API of the legacy struct provider, as encapsulated by PyStructUtils.
Work toward #7010.
RELNOTES: None
PiperOrigin-RevId: 231460993
diff --git a/src/main/java/com/google/devtools/build/docgen/BUILD b/src/main/java/com/google/devtools/build/docgen/BUILD
index a93fcf9..7606312 100644
--- a/src/main/java/com/google/devtools/build/docgen/BUILD
+++ b/src/main/java/com/google/devtools/build/docgen/BUILD
@@ -23,6 +23,7 @@
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/java",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/platform",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi",
@@ -32,6 +33,7 @@
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/java",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/platform",
+ "//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/repository",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test",
"//src/main/java/com/google/devtools/common/options",
@@ -84,6 +86,7 @@
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/java:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/platform:srcs",
+ "//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/repository:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test:srcs",
"//src/main/java/com/google/devtools/build/skydoc/rendering:srcs",
diff --git a/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java b/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java
index 532f1e5..caa91de 100644
--- a/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java
+++ b/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java
@@ -25,6 +25,7 @@
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.java.JavaBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.platform.PlatformBootstrap;
+import com.google.devtools.build.lib.skylarkbuildapi.python.PyBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.repository.RepositoryBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.test.TestingBootstrap;
import com.google.devtools.build.lib.syntax.MethodLibrary;
@@ -55,6 +56,7 @@
import com.google.devtools.build.skydoc.fakebuildapi.java.FakeJavaInfo.FakeJavaInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.java.FakeJavaProtoCommon;
import com.google.devtools.build.skydoc.fakebuildapi.platform.FakePlatformCommon;
+import com.google.devtools.build.skydoc.fakebuildapi.python.FakePyInfo.FakePyInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.repository.FakeRepositoryModule;
import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisFailureInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisTestResultInfoProvider;
@@ -186,6 +188,7 @@
new FakeJavaProtoCommon(),
new FakeJavaCcLinkParamsProvider.Provider());
PlatformBootstrap platformBootstrap = new PlatformBootstrap(new FakePlatformCommon());
+ PyBootstrap pyBootstrap = new PyBootstrap(new FakePyInfoProvider());
RepositoryBootstrap repositoryBootstrap = new RepositoryBootstrap(new FakeRepositoryModule());
TestingBootstrap testingBootstrap = new TestingBootstrap(new FakeTestingModule(),
new FakeAnalysisFailureInfoProvider(),
@@ -198,6 +201,7 @@
configBootstrap.addBindingsToBuilder(envBuilder);
javaBootstrap.addBindingsToBuilder(envBuilder);
platformBootstrap.addBindingsToBuilder(envBuilder);
+ pyBootstrap.addBindingsToBuilder(envBuilder);
repositoryBootstrap.addBindingsToBuilder(envBuilder);
testingBootstrap.addBindingsToBuilder(envBuilder);
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 74f885f..b7e94345 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -753,6 +753,7 @@
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/apple",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/java",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/skyframe",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
@@ -1119,11 +1120,13 @@
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/lib/rules/cpp",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
"//src/main/java/com/google/devtools/common/options",
"//src/main/protobuf:crosstool_config_java_proto",
"//src/main/protobuf:extra_actions_base_java_proto",
"//third_party:guava",
+ "//third_party:jsr305",
"//third_party/protobuf:protobuf_java",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 3b5ca84..cb06a9b 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -82,11 +82,13 @@
import com.google.devtools.build.lib.rules.proto.ProtoConfiguration;
import com.google.devtools.build.lib.rules.proto.ProtoInfo;
import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainRule;
+import com.google.devtools.build.lib.rules.python.PyInfo;
import com.google.devtools.build.lib.rules.python.PythonConfigurationLoader;
import com.google.devtools.build.lib.rules.repository.CoreWorkspaceRules;
import com.google.devtools.build.lib.rules.repository.NewLocalRepositoryRule;
import com.google.devtools.build.lib.rules.test.TestingSupportRules;
import com.google.devtools.build.lib.skylarkbuildapi.android.AndroidBootstrap;
+import com.google.devtools.build.lib.skylarkbuildapi.python.PyBootstrap;
import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.util.ResourceFileLoader;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -342,6 +344,8 @@
builder.addRuleDefinition(new BazelPyBinaryRule());
builder.addRuleDefinition(new BazelPyTestRule());
builder.addRuleDefinition(new BazelPyRuntimeRule());
+
+ builder.addSkylarkBootstrap(new PyBootstrap(PyInfo.PROVIDER));
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyInfo.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyInfo.java
new file mode 100644
index 0000000..2ea0b58
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyInfo.java
@@ -0,0 +1,251 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.rules.python;
+
+import com.google.common.base.Preconditions;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.BuiltinProvider;
+import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.skylarkbuildapi.python.PyInfoApi;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/** Instance of the provider type for the Python rules. */
+public class PyInfo extends Info implements PyInfoApi<Artifact> {
+
+ public static final String STARLARK_NAME = "PyInfo";
+
+ public static final PyInfoProvider PROVIDER = new PyInfoProvider();
+
+ /**
+ * Returns true if the given depset has a content type that is a subtype of the given class, and
+ * has an order compatible with the given order.
+ */
+ private static boolean depsetHasTypeAndCompatibleOrder(
+ SkylarkNestedSet depset, Class<?> clazz, Order order) {
+ // Work around #7266 by special-casing the empty set in the type check.
+ boolean typeOk = depset.isEmpty() || depset.getContentType().canBeCastTo(clazz);
+ boolean orderOk = depset.getOrder().isCompatible(order);
+ return typeOk && orderOk;
+ }
+
+ /**
+ * Returns the type name of a value and possibly additional description.
+ *
+ * <p>For depsets, this includes its content type and order.
+ */
+ private static String describeType(Object value) {
+ String typeName = EvalUtils.getDataTypeName(value, /*fullDetails=*/ true);
+ if (value instanceof SkylarkNestedSet) {
+ return ((SkylarkNestedSet) value).getOrder().getSkylarkName() + "-ordered " + typeName;
+ } else {
+ return typeName;
+ }
+ }
+
+ private final SkylarkNestedSet transitiveSources;
+ private final boolean usesSharedLibraries;
+ private final SkylarkNestedSet imports;
+ private final boolean hasPy2OnlySources;
+ private final boolean hasPy3OnlySources;
+
+ private PyInfo(
+ @Nullable Location location,
+ SkylarkNestedSet transitiveSources,
+ boolean usesSharedLibraries,
+ SkylarkNestedSet imports,
+ boolean hasPy2OnlySources,
+ boolean hasPy3OnlySources) {
+ super(PROVIDER, location);
+ Preconditions.checkArgument(
+ depsetHasTypeAndCompatibleOrder(transitiveSources, Artifact.class, Order.COMPILE_ORDER));
+ // TODO(brandjon): PyCommon currently requires COMPILE_ORDER, but we'll probably want to change
+ // that to NAIVE_LINK (preorder). In the meantime, order isn't an invariant of the provider
+ // itself, so we use STABLE here to accept any order.
+ Preconditions.checkArgument(
+ depsetHasTypeAndCompatibleOrder(imports, String.class, Order.STABLE_ORDER));
+ this.transitiveSources = transitiveSources;
+ this.usesSharedLibraries = usesSharedLibraries;
+ this.imports = imports;
+ this.hasPy2OnlySources = hasPy2OnlySources;
+ this.hasPy3OnlySources = hasPy3OnlySources;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // PyInfo implements value equality, but note that it contains identity-equality fields
+ // (depsets), so you generally shouldn't rely on equality comparisons.
+ if (!(other instanceof PyInfo)) {
+ return false;
+ }
+ PyInfo otherInfo = (PyInfo) other;
+ return (this.transitiveSources.equals(otherInfo.transitiveSources)
+ && this.usesSharedLibraries == otherInfo.usesSharedLibraries
+ && this.imports.equals(otherInfo.imports)
+ && this.hasPy2OnlySources == otherInfo.hasPy2OnlySources
+ && this.hasPy3OnlySources == otherInfo.hasPy3OnlySources);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ PyInfo.class,
+ transitiveSources,
+ usesSharedLibraries,
+ imports,
+ hasPy2OnlySources,
+ hasPy3OnlySources);
+ }
+
+ @Override
+ public SkylarkNestedSet getTransitiveSources() {
+ return transitiveSources;
+ }
+
+ @Override
+ public boolean getUsesSharedLibraries() {
+ return usesSharedLibraries;
+ }
+
+ @Override
+ public SkylarkNestedSet getImports() {
+ return imports;
+ }
+
+ @Override
+ public boolean getHasPy2OnlySources() {
+ return hasPy2OnlySources;
+ }
+
+ @Override
+ public boolean getHasPy3OnlySources() {
+ return hasPy3OnlySources;
+ }
+
+ /** The singular PyInfo provider type object. */
+ public static class PyInfoProvider extends BuiltinProvider<PyInfo>
+ implements PyInfoApi.PyInfoProviderApi {
+
+ private PyInfoProvider() {
+ super(STARLARK_NAME, PyInfo.class);
+ }
+
+ @Override
+ public PyInfo constructor(
+ SkylarkNestedSet transitiveSources,
+ boolean usesSharedLibraries,
+ Object importsUncast,
+ boolean hasPy2OnlySources,
+ boolean hasPy3OnlySources,
+ Location loc)
+ throws EvalException {
+ SkylarkNestedSet imports =
+ importsUncast.equals(Runtime.UNBOUND)
+ ? SkylarkNestedSet.of(String.class, NestedSetBuilder.emptySet(Order.COMPILE_ORDER))
+ : (SkylarkNestedSet) importsUncast;
+
+ if (!depsetHasTypeAndCompatibleOrder(
+ transitiveSources, Artifact.class, Order.COMPILE_ORDER)) {
+ throw new EvalException(
+ loc,
+ String.format(
+ "'transitive_sources' field should be a postorder-compatible depset of Files (got "
+ + "a '%s')",
+ describeType(transitiveSources)));
+ }
+ if (!depsetHasTypeAndCompatibleOrder(imports, String.class, Order.STABLE_ORDER)) {
+ throw new EvalException(
+ loc,
+ String.format(
+ "'imports' field should be a depset of strings (got a '%s')",
+ describeType(imports)));
+ }
+
+ return new PyInfo(
+ loc,
+ transitiveSources,
+ usesSharedLibraries,
+ imports,
+ hasPy2OnlySources,
+ hasPy3OnlySources);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for {@link PyInfo}. */
+ public static class Builder {
+ Location location = null;
+ NestedSet<Artifact> transitiveSources = NestedSetBuilder.emptySet(Order.COMPILE_ORDER);
+ boolean usesSharedLibraries = false;
+ NestedSet<String> imports = NestedSetBuilder.emptySet(Order.COMPILE_ORDER);
+ boolean hasPy2OnlySources = false;
+ boolean hasPy3OnlySources = false;
+
+ // Use the static builder() method instead.
+ private Builder() {}
+
+ public Builder setLocation(Location location) {
+ this.location = location;
+ return this;
+ }
+
+ public Builder setTransitiveSources(NestedSet<Artifact> transitiveSources) {
+ this.transitiveSources = transitiveSources;
+ return this;
+ }
+
+ public Builder setUsesSharedLibraries(boolean usesSharedLibraries) {
+ this.usesSharedLibraries = usesSharedLibraries;
+ return this;
+ }
+
+ public Builder setImports(NestedSet<String> imports) {
+ this.imports = imports;
+ return this;
+ }
+
+ public Builder setHasPy2OnlySources(boolean hasPy2OnlySources) {
+ this.hasPy2OnlySources = hasPy2OnlySources;
+ return this;
+ }
+
+ public Builder setHasPy3OnlySources(boolean hasPy3OnlySources) {
+ this.hasPy3OnlySources = hasPy3OnlySources;
+ return this;
+ }
+
+ public PyInfo build() {
+ Preconditions.checkNotNull(transitiveSources);
+ return new PyInfo(
+ location,
+ SkylarkNestedSet.of(Artifact.class, transitiveSources),
+ usesSharedLibraries,
+ SkylarkNestedSet.of(String.class, imports),
+ hasPy2OnlySources,
+ hasPy3OnlySources);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyStructUtils.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyStructUtils.java
index 5e3ae8c..f2a45b9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PyStructUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyStructUtils.java
@@ -28,7 +28,7 @@
import com.google.devtools.build.lib.syntax.SkylarkType;
/** Static helper class for creating and accessing instances of the legacy "py" struct provider. */
-// TODO(#7010): Replace this with a real provider.
+// TODO(#7010): Remove this in favor of PyInfo.
public class PyStructUtils {
// Disable construction.
@@ -76,7 +76,7 @@
builder.put(USES_SHARED_LIBRARIES, false);
builder.put(
IMPORTS,
- SkylarkNestedSet.of(String.class, NestedSetBuilder.<String>compileOrder().build()));
+ SkylarkNestedSet.of(String.class, NestedSetBuilder.<String>emptySet(Order.COMPILE_ORDER)));
builder.put(HAS_PY2_ONLY_SOURCES, false);
builder.put(HAS_PY3_ONLY_SOURCES, false);
DEFAULTS = builder.build();
@@ -110,7 +110,7 @@
"'%s' provider's '%s' field should be a depset of Files (got a '%s')",
PROVIDER_NAME,
TRANSITIVE_SOURCES,
- EvalUtils.getDataTypeNameFromClass(fieldValue.getClass()));
+ EvalUtils.getDataTypeName(fieldValue, /*fullDetails=*/ true));
NestedSet<Artifact> unwrappedValue = castValue.getSet(Artifact.class);
if (!unwrappedValue.getOrder().isCompatible(Order.COMPILE_ORDER)) {
throw new EvalException(
@@ -137,7 +137,7 @@
"'%s' provider's '%s' field should be a boolean (got a '%s')",
PROVIDER_NAME,
USES_SHARED_LIBRARIES,
- EvalUtils.getDataTypeNameFromClass(fieldValue.getClass()));
+ EvalUtils.getDataTypeName(fieldValue, /*fullDetails=*/ true));
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD
index 73ad12c..47a5694 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD
@@ -19,6 +19,7 @@
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/java:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/platform:srcs",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test:srcs",
],
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/BUILD b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/BUILD
new file mode 100644
index 0000000..220dcb1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/BUILD
@@ -0,0 +1,28 @@
+# Description:
+# This package contains interfaces representing the skylark "build API"
+# (but not the implementation of that API). Ultimately, this package
+# may be broken out of the Bazel package hierarchy to be standalone.
+# Thus, this package should not depend on Bazel-specific packages (only
+# those which contain pure-Skylark concepts, such as the interpreter or
+# annotation interfaces).
+
+package(default_visibility = ["//src:__subpackages__"])
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+java_library(
+ name = "python",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+ "//src/main/java/com/google/devtools/build/lib:syntax",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi",
+ "//third_party:guava",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/PyBootstrap.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/PyBootstrap.java
new file mode 100644
index 0000000..5c182de
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/PyBootstrap.java
@@ -0,0 +1,34 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkbuildapi.python;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.skylarkbuildapi.Bootstrap;
+import com.google.devtools.build.lib.skylarkbuildapi.python.PyInfoApi.PyInfoProviderApi;
+
+/** {@link Bootstrap} for Starlark objects related to the Python rules. */
+public class PyBootstrap implements Bootstrap {
+
+ private final PyInfoProviderApi pyInfoProviderApi;
+
+ public PyBootstrap(PyInfoProviderApi pyInfoProviderApi) {
+ this.pyInfoProviderApi = pyInfoProviderApi;
+ }
+
+ @Override
+ public void addBindingsToBuilder(ImmutableMap.Builder<String, Object> builder) {
+ builder.put("PyInfo", pyInfoProviderApi);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/PyInfoApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/PyInfoApi.java
new file mode 100644
index 0000000..4fbb185
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python/PyInfoApi.java
@@ -0,0 +1,136 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkbuildapi.python;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
+import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkConstructor;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/** Provider instance for the Python rules. */
+@SkylarkModule(
+ name = "PyInfo",
+ doc = "Encapsulates information provided by the Python rules.",
+ category = SkylarkModuleCategory.PROVIDER)
+public interface PyInfoApi<FileT extends FileApi> extends SkylarkValue {
+
+ @SkylarkCallable(
+ name = "transitive_sources",
+ structField = true,
+ doc =
+ "A (<code>postorder</code>-compatible) depset of <code>.py</code> files appearing in the "
+ + "target's <code>srcs</code> and the <code>srcs</code> of the target's transitive "
+ + "<code>deps</code>.")
+ SkylarkNestedSet getTransitiveSources();
+
+ @SkylarkCallable(
+ name = "uses_shared_libraries",
+ structField = true,
+ doc =
+ "Whether any of this target's transitive <code>deps</code> has a shared library file "
+ + "(such as a <code>.so</code> file)."
+ + ""
+ + "<p>This field is currently unused in Bazel and may go away in the future.")
+ boolean getUsesSharedLibraries();
+
+ @SkylarkCallable(
+ name = "imports",
+ structField = true,
+ doc =
+ "A depset of import path strings to be added to the <code>PYTHONPATH</code> of "
+ + "executable Python targets. These are accumulated from the transitive "
+ + "<code>deps</code>."
+ + ""
+ + "<p>The order of the depset is not guaranteed and may be changed in the future. It "
+ + "is recommended to use <code>default</code> order (the default).")
+ SkylarkNestedSet getImports();
+
+ @SkylarkCallable(
+ name = "has_py2_only_sources",
+ structField = true,
+ doc = "Whether any of this target's transitive sources requires a Python 2 runtime.")
+ boolean getHasPy2OnlySources();
+
+ @SkylarkCallable(
+ name = "has_py3_only_sources",
+ structField = true,
+ doc = "Whether any of this target's transitive sources requires a Python 3 runtime.")
+ boolean getHasPy3OnlySources();
+
+ /** Provider type for {@link PyInfoApi} objects. */
+ @SkylarkModule(name = "Provider", documented = false, doc = "")
+ interface PyInfoProviderApi extends ProviderApi {
+
+ @SkylarkCallable(
+ name = "PyInfo",
+ doc = "The <code>PyInfo</code> constructor.",
+ parameters = {
+ @Param(
+ name = "transitive_sources",
+ type = SkylarkNestedSet.class,
+ generic1 = FileApi.class,
+ positional = false,
+ named = true,
+ doc = "The value for the new object's <code>transitive_sources</code> field."),
+ @Param(
+ name = "uses_shared_libraries",
+ type = Boolean.class,
+ positional = false,
+ named = true,
+ defaultValue = "False",
+ doc = "The value for the new object's <code>uses_shared_libraries</code> field."),
+ @Param(
+ name = "imports",
+ type = SkylarkNestedSet.class,
+ generic1 = String.class,
+ positional = false,
+ named = true,
+ defaultValue = "unbound",
+ doc = "The value for the new object's <code>imports</code> field."),
+ @Param(
+ name = "has_py2_only_sources",
+ type = Boolean.class,
+ positional = false,
+ named = true,
+ defaultValue = "False",
+ doc = "The value for the new object's <code>has_py2_only_sources</code> field."),
+ @Param(
+ name = "has_py3_only_sources",
+ type = Boolean.class,
+ positional = false,
+ named = true,
+ defaultValue = "False",
+ doc = "The value for the new object's <code>has_py3_only_sources</code> field.")
+ },
+ selfCall = true,
+ useLocation = true)
+ @SkylarkConstructor(objectType = PyInfoApi.class, receiverNameForDoc = "PyInfo")
+ PyInfoApi<?> constructor(
+ SkylarkNestedSet transitiveSources,
+ boolean usesSharedLibraries,
+ Object importsUncast,
+ boolean hasPy2OnlySources,
+ boolean hasPy3OnlySources,
+ Location loc)
+ throws EvalException;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
index 865801f..eabff4e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
@@ -223,7 +223,9 @@
return new Parameter.Star<>(Identifier.of(param.name()), officialType);
} else if (mandatory) {
return new Parameter.Mandatory<>(Identifier.of(param.name()), officialType);
- } else if (defaultValue != null && enforcedType != null) {
+ } else if (defaultValue != null
+ && !defaultValue.equals(Runtime.UNBOUND)
+ && enforcedType != null) {
Preconditions.checkArgument(enforcedType.contains(defaultValue),
"In function '%s', parameter '%s' has default value %s that isn't of enforced type %s",
name, param.name(), Printer.repr(defaultValue), enforcedType);
diff --git a/src/main/java/com/google/devtools/build/skydoc/BUILD b/src/main/java/com/google/devtools/build/skydoc/BUILD
index c6e3688..0fbe823 100644
--- a/src/main/java/com/google/devtools/build/skydoc/BUILD
+++ b/src/main/java/com/google/devtools/build/skydoc/BUILD
@@ -22,6 +22,7 @@
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/java:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/platform:srcs",
+ "//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/repository:srcs",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test:srcs",
"//src/main/java/com/google/devtools/build/skydoc/rendering:srcs",
@@ -64,6 +65,7 @@
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/java",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/platform",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
@@ -74,6 +76,7 @@
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/java",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/platform",
+ "//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/repository",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test",
"//src/main/java/com/google/devtools/build/skydoc/rendering",
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
index bb64b94..16855c9 100644
--- a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -47,6 +47,7 @@
import com.google.devtools.build.lib.skylarkbuildapi.java.GeneratedExtensionRegistryProviderApi;
import com.google.devtools.build.lib.skylarkbuildapi.java.JavaBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.platform.PlatformBootstrap;
+import com.google.devtools.build.lib.skylarkbuildapi.python.PyBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.repository.RepositoryBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.test.TestingBootstrap;
import com.google.devtools.build.lib.syntax.BaseFunction;
@@ -86,6 +87,7 @@
import com.google.devtools.build.skydoc.fakebuildapi.java.FakeJavaInfo.FakeJavaInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.java.FakeJavaProtoCommon;
import com.google.devtools.build.skydoc.fakebuildapi.platform.FakePlatformCommon;
+import com.google.devtools.build.skydoc.fakebuildapi.python.FakePyInfo.FakePyInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.repository.FakeRepositoryModule;
import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisFailureInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisTestResultInfoProvider;
@@ -477,6 +479,7 @@
new FakeJavaProtoCommon(),
new FakeJavaCcLinkParamsProvider.Provider());
PlatformBootstrap platformBootstrap = new PlatformBootstrap(new FakePlatformCommon());
+ PyBootstrap pyBootstrap = new PyBootstrap(new FakePyInfoProvider());
RepositoryBootstrap repositoryBootstrap = new RepositoryBootstrap(new FakeRepositoryModule());
TestingBootstrap testingBootstrap = new TestingBootstrap(new FakeTestingModule(),
new FakeAnalysisFailureInfoProvider(),
@@ -493,6 +496,7 @@
configBootstrap.addBindingsToBuilder(envBuilder);
javaBootstrap.addBindingsToBuilder(envBuilder);
platformBootstrap.addBindingsToBuilder(envBuilder);
+ pyBootstrap.addBindingsToBuilder(envBuilder);
repositoryBootstrap.addBindingsToBuilder(envBuilder);
testingBootstrap.addBindingsToBuilder(envBuilder);
addNonBootstrapGlobals(envBuilder);
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python/BUILD b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python/BUILD
new file mode 100644
index 0000000..5b4cf68
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python/BUILD
@@ -0,0 +1,22 @@
+package(
+ default_visibility = ["//src:__subpackages__"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+java_library(
+ name = "python",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+ "//src/main/java/com/google/devtools/build/lib:syntax",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python/FakePyInfo.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python/FakePyInfo.java
new file mode 100644
index 0000000..b495e04
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/python/FakePyInfo.java
@@ -0,0 +1,73 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.skydoc.fakebuildapi.python;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
+import com.google.devtools.build.lib.skylarkbuildapi.python.PyInfoApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/** Fake implementation of {@link PyInfoApi}. */
+public class FakePyInfo implements PyInfoApi<FileApi> {
+
+ @Override
+ public SkylarkNestedSet getTransitiveSources() {
+ return null;
+ }
+
+ @Override
+ public boolean getUsesSharedLibraries() {
+ return false;
+ }
+
+ @Override
+ public SkylarkNestedSet getImports() {
+ return null;
+ }
+
+ @Override
+ public boolean getHasPy2OnlySources() {
+ return false;
+ }
+
+ @Override
+ public boolean getHasPy3OnlySources() {
+ return false;
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+
+ /** Fake implementation of {@link PyInfoProviderApi}. */
+ public static class FakePyInfoProvider implements PyInfoProviderApi {
+
+ @Override
+ public PyInfoApi<?> constructor(
+ SkylarkNestedSet transitiveSources,
+ boolean usesSharedLibraries,
+ Object importsUncast,
+ boolean hasPy2OnlySources,
+ boolean hasPy3OnlySources,
+ Location loc)
+ throws EvalException {
+ return new FakePyInfo();
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/BUILD b/src/test/java/com/google/devtools/build/lib/rules/python/BUILD
index 261a85d..422e6b2 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/BUILD
@@ -14,6 +14,7 @@
tests = [
":BazelPythonConfigurationTest",
":PyBinaryConfiguredTargetTest",
+ ":PyInfoTest",
":PyLibraryConfiguredTargetTest",
":PyProviderUtilsTest",
":PyStructUtilsTest",
@@ -204,6 +205,23 @@
)
java_test(
+ name = "PyInfoTest",
+ srcs = ["PyInfoTest.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:python-rules",
+ "//src/main/java/com/google/devtools/build/lib/actions",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
+ "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
+ "//src/test/java/com/google/devtools/build/lib:analysis_testutil",
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//src/test/java/com/google/devtools/build/lib/skylark:testutil",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
name = "PythonStarlarkApiTest",
srcs = ["PythonStarlarkApiTest.java"],
deps = [
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java b/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java
new file mode 100644
index 0000000..db5d3af
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java
@@ -0,0 +1,176 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.rules.python;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link PyInfo}. */
+@RunWith(JUnit4.class)
+public class PyInfoTest extends SkylarkTestCase {
+
+ private static final Location dummyLoc =
+ new Location(0, 0) {
+ @Override
+ public PathFragment getPath() {
+ return null;
+ }
+ };
+
+ private Artifact dummyArtifact;
+
+ @Before
+ public void setUp() throws Exception {
+ dummyArtifact = getSourceArtifact("dummy");
+ update("PyInfo", PyInfo.PROVIDER);
+ update("dummy_file", dummyArtifact);
+ }
+
+ /** We need this because {@code NestedSet}s don't have value equality. */
+ private static void assertHasOrderAndContainsExactly(
+ NestedSet<?> set, Order order, Object... values) {
+ assertThat(set.getOrder()).isEqualTo(order);
+ assertThat(set).containsExactly(values);
+ }
+
+ /** Checks values set by the builder. */
+ @Test
+ public void builderExplicit() throws Exception {
+ NestedSet<Artifact> sources = NestedSetBuilder.create(Order.COMPILE_ORDER, dummyArtifact);
+ NestedSet<String> imports = NestedSetBuilder.create(Order.COMPILE_ORDER, "abc");
+ PyInfo info =
+ PyInfo.builder()
+ .setLocation(dummyLoc)
+ .setTransitiveSources(sources)
+ .setUsesSharedLibraries(true)
+ .setImports(imports)
+ .setHasPy2OnlySources(true)
+ .setHasPy3OnlySources(true)
+ .build();
+ assertThat(info.getCreationLoc()).isEqualTo(dummyLoc);
+ assertHasOrderAndContainsExactly(
+ info.getTransitiveSources().getSet(Artifact.class), Order.COMPILE_ORDER, dummyArtifact);
+ assertThat(info.getUsesSharedLibraries()).isTrue();
+ assertHasOrderAndContainsExactly(
+ info.getImports().getSet(String.class), Order.COMPILE_ORDER, "abc");
+ assertThat(info.getHasPy2OnlySources()).isTrue();
+ assertThat(info.getHasPy3OnlySources()).isTrue();
+ }
+
+ /** Checks the defaults set by the builder. */
+ @Test
+ public void builderDefaults() throws Exception {
+ // transitive_sources is mandatory, so create a dummy value but no need to assert on it.
+ NestedSet<Artifact> sources = NestedSetBuilder.create(Order.COMPILE_ORDER, dummyArtifact);
+ PyInfo info = PyInfo.builder().setTransitiveSources(sources).build();
+ assertThat(info.getCreationLoc()).isEqualTo(Location.BUILTIN);
+ assertThat(info.getUsesSharedLibraries()).isFalse();
+ assertHasOrderAndContainsExactly(info.getImports().getSet(String.class), Order.COMPILE_ORDER);
+ assertThat(info.getHasPy2OnlySources()).isFalse();
+ assertThat(info.getHasPy3OnlySources()).isFalse();
+ }
+
+ @Test
+ public void starlarkConstructor() throws Exception {
+ eval(
+ "info = PyInfo(",
+ " transitive_sources = depset(direct=[dummy_file]),",
+ " uses_shared_libraries = True,",
+ " imports = depset(direct=['abc']),",
+ " has_py2_only_sources = True,",
+ " has_py3_only_sources = True,",
+ ")");
+ PyInfo info = (PyInfo) lookup("info");
+ assertThat(info.getCreationLoc().getStartOffset()).isEqualTo(7);
+ assertHasOrderAndContainsExactly(
+ info.getTransitiveSources().getSet(Artifact.class), Order.STABLE_ORDER, dummyArtifact);
+ assertThat(info.getUsesSharedLibraries()).isTrue();
+ assertHasOrderAndContainsExactly(
+ info.getImports().getSet(String.class), Order.STABLE_ORDER, "abc");
+ assertThat(info.getHasPy2OnlySources()).isTrue();
+ assertThat(info.getHasPy3OnlySources()).isTrue();
+ }
+
+ @Test
+ public void starlarkConstructorDefaults() throws Exception {
+ eval("info = PyInfo(transitive_sources = depset(direct=[dummy_file]))");
+ PyInfo info = (PyInfo) lookup("info");
+ assertThat(info.getCreationLoc().getStartOffset()).isEqualTo(7);
+ assertHasOrderAndContainsExactly(
+ info.getTransitiveSources().getSet(Artifact.class), Order.STABLE_ORDER, dummyArtifact);
+ assertThat(info.getUsesSharedLibraries()).isFalse();
+ assertHasOrderAndContainsExactly(info.getImports().getSet(String.class), Order.COMPILE_ORDER);
+ assertThat(info.getHasPy2OnlySources()).isFalse();
+ assertThat(info.getHasPy3OnlySources()).isFalse();
+ }
+
+ @Test
+ public void starlarkConstructorErrors_TransitiveSources() throws Exception {
+ checkEvalErrorContains(
+ "'transitive_sources' has no default value", //
+ "PyInfo()");
+ checkEvalErrorContains(
+ "expected value of type 'depset of Files' for parameter 'transitive_sources'",
+ "PyInfo(transitive_sources = 'abc')");
+ checkEvalErrorContains(
+ "expected value of type 'depset of Files' for parameter 'transitive_sources'",
+ "PyInfo(transitive_sources = depset(direct=['abc']))");
+ checkEvalErrorContains(
+ "'transitive_sources' field should be a postorder-compatible depset of Files",
+ "PyInfo(transitive_sources = depset(direct=[dummy_file], order='preorder'))");
+ }
+
+ @Test
+ public void starlarkConstructorErrors_UsesSharedLibraries() throws Exception {
+ checkEvalErrorContains(
+ "expected value of type 'bool' for parameter 'uses_shared_libraries'",
+ "PyInfo(transitive_sources = depset([]), uses_shared_libraries = 'abc')");
+ }
+
+ @Test
+ public void starlarkConstructorErrors_Imports() throws Exception {
+ checkEvalErrorContains(
+ "expected value of type 'depset of strings' for parameter 'imports'",
+ "PyInfo(transitive_sources = depset([]), imports = 'abc')");
+ checkEvalErrorContains(
+ "expected value of type 'depset of strings' for parameter 'imports'",
+ "PyInfo(transitive_sources = depset([]), imports = depset(direct=[123]))");
+ }
+
+ @Test
+ public void starlarkConstructorErrors_HasPy2OnlySources() throws Exception {
+ checkEvalErrorContains(
+ "expected value of type 'bool' for parameter 'has_py2_only_sources'",
+ "PyInfo(transitive_sources = depset([]), has_py2_only_sources = 'abc')");
+ }
+
+ @Test
+ public void starlarkConstructorErrors_HasPy3OnlySources() throws Exception {
+ checkEvalErrorContains(
+ "expected value of type 'bool' for parameter 'has_py3_only_sources'",
+ "PyInfo(transitive_sources = depset([]), has_py3_only_sources = 'abc')");
+ }
+}