Skip to content

Commit 258dfe9

Browse files
adonovancopybara-github
authored andcommitted
blaze: add 'json' module to all Starlark environments
This change predeclares 'json', the new Starlark module for JSON encoding/decoding/indenting, in all Bazel Starlark environments (alongside depset, select, etc). The new function works for any legal value, not just struct, and avoids polluting the struct field namespace. struct.to_json is deprecated, along with struct.to_proto, and will be disabled by the new flag --incompatible_struct_has_no_methods. (The replacement for to_proto will be added shortly.) Updates bazelbuild/starlark#83 Updates #3732 Updates #1813 RELNOTES: The Starlark json module is now available. Use json.encode(x) to encode a Starlark value as JSON. struct.to_json(x) is deprecated and will be disabled by the --incompatible_struct_has_no_methods flag. PiperOrigin-RevId: 338259618
1 parent 07f092e commit 258dfe9

File tree

8 files changed

+50
-6
lines changed

8 files changed

+50
-6
lines changed

src/main/java/com/google/devtools/build/docgen/StarlarkDocumentationProcessor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ static Category of(StarlarkBuiltin annot) {
236236
case DocCategory.NONE:
237237
return NONE;
238238
case "core": // interpreter built-ins (e.g. int)
239+
case "core.lib": // Starlark standard modules (e.g. json)
239240
return CORE;
240241
case "": // no annotation
241242
return TOP_LEVEL_TYPE;

src/main/java/com/google/devtools/build/lib/packages/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ java_library(
4444
"//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/core",
4545
"//src/main/java/com/google/devtools/build/lib/util",
4646
"//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
47-
"//src/main/java/com/google/devtools/build/lib/util:exit_code",
4847
"//src/main/java/com/google/devtools/build/lib/util:filetype",
4948
"//src/main/java/com/google/devtools/build/lib/util:string",
5049
"//src/main/java/com/google/devtools/build/lib/vfs",
@@ -53,6 +52,7 @@ java_library(
5352
"//src/main/java/com/google/devtools/common/options",
5453
"//src/main/java/net/starlark/java/annot",
5554
"//src/main/java/net/starlark/java/eval",
55+
"//src/main/java/net/starlark/java/lib/json",
5656
"//src/main/java/net/starlark/java/spelling",
5757
"//src/main/java/net/starlark/java/syntax",
5858
"//src/main/protobuf:build_java_proto",

src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import net.starlark.java.eval.Sequence;
3737
import net.starlark.java.eval.Starlark;
3838
import net.starlark.java.eval.StarlarkThread;
39+
import net.starlark.java.lib.json.Json;
3940
import net.starlark.java.syntax.Location;
4041

4142
/**
@@ -51,15 +52,16 @@ public final class StarlarkLibrary {
5152
private StarlarkLibrary() {} // uninstantiable
5253

5354
/**
54-
* A library of Starlark functions (keyed by name) that are not part of core Starlark but are
55-
* common to all Bazel Starlark file environments (BUILD, .bzl, and WORKSPACE). Examples: depset,
56-
* select.
55+
* A library of Starlark values (keyed by name) that are not part of core Starlark but are common
56+
* to all Bazel Starlark file environments (BUILD, .bzl, and WORKSPACE). Examples: depset, select,
57+
* json.
5758
*/
5859
public static final ImmutableMap<String, Object> COMMON = initCommon();
5960

6061
private static ImmutableMap<String, Object> initCommon() {
6162
ImmutableMap.Builder<String, Object> env = ImmutableMap.builder();
6263
Starlark.addMethods(env, new CommonLibrary());
64+
Starlark.addModule(env, Json.INSTANCE);
6365
return env.build();
6466
}
6567

src/main/java/com/google/devtools/build/lib/packages/semantics/BuildLanguageOptions.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,21 @@ public class BuildLanguageOptions extends OptionsBase implements Serializable {
257257
+ " https://github.com/bazelbuild/bazel/issues/8830 for details.")
258258
public boolean experimentalAllowTagsPropagation;
259259

260+
@Option(
261+
name = "incompatible_struct_has_no_methods",
262+
defaultValue = "false",
263+
documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS,
264+
effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS},
265+
metadataTags = {
266+
OptionMetadataTag.INCOMPATIBLE_CHANGE,
267+
OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
268+
},
269+
help =
270+
"Disables the to_json and to_proto methods of struct, which pollute the struct field"
271+
+ " namespace. Instead, use json.encode or json.encode_indent for JSON, or"
272+
+ " proto.encode_text for textproto.")
273+
public boolean incompatibleStructHasNoMethods;
274+
260275
@Option(
261276
name = "incompatible_always_check_depset_elements",
262277
defaultValue = "true",
@@ -637,6 +652,7 @@ public StarlarkSemantics toStarlarkSemantics() {
637652
.setBool(INCOMPATIBLE_RUN_SHELL_COMMAND_STRING, incompatibleRunShellCommandString)
638653
.setBool(
639654
StarlarkSemantics.INCOMPATIBLE_STRING_REPLACE_COUNT, incompatibleStringReplaceCount)
655+
.setBool(INCOMPATIBLE_STRUCT_HAS_NO_METHODS, incompatibleStructHasNoMethods)
640656
.setBool(
641657
INCOMPATIBLE_VISIBILITY_PRIVATE_ATTRIBUTES_AT_DEFINITION,
642658
incompatibleVisibilityPrivateAttributesAtDefinition)
@@ -720,6 +736,8 @@ public StarlarkSemantics toStarlarkSemantics() {
720736
"-incompatible_restrict_string_escapes";
721737
public static final String INCOMPATIBLE_RUN_SHELL_COMMAND_STRING =
722738
"-incompatible_run_shell_command_string";
739+
public static final String INCOMPATIBLE_STRUCT_HAS_NO_METHODS =
740+
"-incompatible_struct_has_no_methods";
723741
public static final String INCOMPATIBLE_USE_CC_CONFIGURE_FROM_RULES_CC =
724742
"-incompatible_use_cc_configure_from_rules";
725743
public static final String INCOMPATIBLE_VISIBILITY_PRIVATE_ATTRIBUTES_AT_DEFINITION =

src/main/java/com/google/devtools/build/lib/starlarkbuildapi/core/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ java_library(
2525
srcs = glob(["*.java"]),
2626
deps = [
2727
"//src/main/java/com/google/devtools/build/docgen/annot",
28+
"//src/main/java/com/google/devtools/build/lib/packages/semantics",
2829
"//src/main/java/net/starlark/java/annot",
2930
"//src/main/java/net/starlark/java/eval",
3031
"//third_party:guava",

src/main/java/com/google/devtools/build/lib/starlarkbuildapi/core/StructApi.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import com.google.devtools.build.docgen.annot.DocCategory;
1818
import com.google.devtools.build.docgen.annot.StarlarkConstructor;
19+
import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
1920
import net.starlark.java.annot.Param;
2021
import net.starlark.java.annot.StarlarkBuiltin;
2122
import net.starlark.java.annot.StarlarkMethod;
@@ -62,7 +63,9 @@ public interface StructApi extends StarlarkValue {
6263
+ "# key: 2\n"
6364
+ "# value: 1\n"
6465
+ "# }\n"
65-
+ "</pre>")
66+
+ "</pre>",
67+
// TODO(adonovan): CL 338119348 defines proto.encode_text(x) and deprecates this function.
68+
disableWithFlag = BuildLanguageOptions.INCOMPATIBLE_STRUCT_HAS_NO_METHODS)
6669
String toProto() throws EvalException;
6770

6871
@StarlarkMethod(
@@ -82,7 +85,10 @@ public interface StructApi extends StarlarkValue {
8285
+ "struct(key=[struct(inner_key=1), struct(inner_key=2)]).to_json()\n"
8386
+ "# {\"key\":[{\"inner_key\":1},{\"inner_key\":2}]}\n\n"
8487
+ "struct(key=struct(inner_key=struct(inner_inner_key='text'))).to_json()\n"
85-
+ "# {\"key\":{\"inner_key\":{\"inner_inner_key\":\"text\"}}}\n</pre>")
88+
+ "# {\"key\":{\"inner_key\":{\"inner_inner_key\":\"text\"}}}\n</pre>."
89+
+ "<p>Deprecated: instead, use json.encode(x) or json.encode_indent(x), which work"
90+
+ " for values other than structs and do not pollute the struct field namespace. ",
91+
disableWithFlag = BuildLanguageOptions.INCOMPATIBLE_STRUCT_HAS_NO_METHODS)
8692
String toJson() throws EvalException;
8793

8894
/** Callable Provider for new struct objects. */

src/test/java/com/google/devtools/build/lib/packages/semantics/ConsistencyTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ private static BuildLanguageOptions buildRandomOptions(Random rand) throws Excep
151151
"--incompatible_objc_provider_remove_compile_info=" + rand.nextBoolean(),
152152
"--incompatible_run_shell_command_string=" + rand.nextBoolean(),
153153
"--incompatible_string_replace_count=" + rand.nextBoolean(),
154+
"--incompatible_struct_has_no_methods=" + rand.nextBoolean(),
154155
"--incompatible_visibility_private_attributes_at_definition=" + rand.nextBoolean(),
155156
"--incompatible_require_linker_input_cc_api=" + rand.nextBoolean(),
156157
"--incompatible_restrict_string_escapes=" + rand.nextBoolean(),
@@ -207,6 +208,7 @@ private static StarlarkSemantics buildRandomSemantics(Random rand) {
207208
BuildLanguageOptions.INCOMPATIBLE_OBJC_PROVIDER_REMOVE_COMPILE_INFO, rand.nextBoolean())
208209
.setBool(BuildLanguageOptions.INCOMPATIBLE_RUN_SHELL_COMMAND_STRING, rand.nextBoolean())
209210
.setBool(StarlarkSemantics.INCOMPATIBLE_STRING_REPLACE_COUNT, rand.nextBoolean())
211+
.setBool(BuildLanguageOptions.INCOMPATIBLE_STRUCT_HAS_NO_METHODS, rand.nextBoolean())
210212
.setBool(
211213
BuildLanguageOptions.INCOMPATIBLE_VISIBILITY_PRIVATE_ATTRIBUTES_AT_DEFINITION,
212214
rand.nextBoolean())

src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,20 @@ private void checkJson(String from, String expected) throws Exception {
10801080
assertThat(result).isEqualTo(expected);
10811081
}
10821082

1083+
@Test
1084+
public void testStarlarkJsonModule() throws Exception {
1085+
// struct.to_json is deprecated.
1086+
// java.starlark.net's json module is its replacement.
1087+
setBuildLanguageOptions("--incompatible_struct_has_no_methods=false");
1088+
checkJson("json.encode(struct(name=True))", "{\"name\":true}");
1089+
checkJson("json.encode([1, 2])", "[1,2]"); // works for non-structs too
1090+
checkJson("str(dir(struct()))", "[\"to_json\", \"to_proto\"]");
1091+
1092+
setBuildLanguageOptions("--incompatible_struct_has_no_methods=true");
1093+
ev.checkEvalErrorContains("no field or method 'to_json'", "struct(name=True).to_json()");
1094+
checkJson("str(dir(struct()))", "[]"); // no to_{json,proto}
1095+
}
1096+
10831097
@Test
10841098
public void testJsonBooleanFields() throws Exception {
10851099
checkJson("struct(name=True).to_json()", "{\"name\":true}");

0 commit comments

Comments
 (0)