Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 7413c05

Browse files
committed
chore: skip naming analysis during initial type discovery
1 parent 413f8fa commit 7413c05

2 files changed

Lines changed: 92 additions & 5 deletions

File tree

gapic/schema/api.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ def build(
114114
opts: Options = Options(),
115115
prior_protos: Optional[Mapping[str, "Proto"]] = None,
116116
load_services: bool = True,
117+
skip_context_analysis: bool = False,
117118
all_resources: Optional[Mapping[str, wrappers.MessageType]] = None,
118119
) -> "Proto":
119120
"""Build and return a Proto instance.
@@ -130,6 +131,8 @@ def build(
130131
load_services (bool): Toggle whether the proto file should
131132
load its services. Not doing so enables a two-pass fix for
132133
LRO response and metadata types in certain situations.
134+
skip_context_analysis (bool): Toggle whether to skip context
135+
analysis. Defaults to False.
133136
"""
134137
return _ProtoBuilder(
135138
file_descriptor,
@@ -138,6 +141,7 @@ def build(
138141
opts=opts,
139142
prior_protos=prior_protos or {},
140143
load_services=load_services,
144+
skip_context_analysis=skip_context_analysis,
141145
all_resources=all_resources or {},
142146
).proto
143147

@@ -463,8 +467,8 @@ def disambiguate_keyword_sanitize_fname(
463467
naming=naming,
464468
opts=opts,
465469
prior_protos=pre_protos,
466-
# Ugly, ugly hack.
467470
load_services=False,
471+
skip_context_analysis=True,
468472
)
469473

470474
# A file descriptor's file-level resources are NOT visible to any importers.
@@ -1102,6 +1106,7 @@ def __init__(
11021106
opts: Options = Options(),
11031107
prior_protos: Optional[Mapping[str, Proto]] = None,
11041108
load_services: bool = True,
1109+
skip_context_analysis: bool = False,
11051110
all_resources: Optional[Mapping[str, wrappers.MessageType]] = None,
11061111
):
11071112
self.proto_messages: Dict[str, wrappers.MessageType] = {}
@@ -1111,6 +1116,7 @@ def __init__(
11111116
self.file_to_generate = file_to_generate
11121117
self.prior_protos = prior_protos or {}
11131118
self.opts = opts
1119+
self.skip_context_analysis = skip_context_analysis
11141120

11151121
# Iterate over the documentation and place it into a dictionary.
11161122
#
@@ -1217,7 +1223,7 @@ def proto(self) -> Proto:
12171223

12181224
# If this is not a file being generated, we do not need to
12191225
# do anything else.
1220-
if not self.file_to_generate:
1226+
if not self.file_to_generate or self.skip_context_analysis:
12211227
return naive
12221228

12231229
visited_messages: Set[wrappers.MessageType] = set()

tests/unit/schema/test_api.py

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4430,9 +4430,9 @@ def test_method_settings_unsupported_auto_populated_field_field_info_format_rais
44304430
the format of the field is `IPV4`.
44314431
"""
44324432
field_options = descriptor_pb2.FieldOptions()
4433-
field_options.Extensions[field_info_pb2.field_info].format = (
4434-
field_info_pb2.FieldInfo.Format.Value("IPV4")
4435-
)
4433+
field_options.Extensions[
4434+
field_info_pb2.field_info
4435+
].format = field_info_pb2.FieldInfo.Format.Value("IPV4")
44364436
squid = make_field_pb2(
44374437
name="squid", type="TYPE_STRING", options=field_options, number=1
44384438
)
@@ -4499,3 +4499,84 @@ def test_method_settings_invalid_multiple_issues():
44994499
assert re.match(".*squid.*not.*uuid4.*", error_yaml[method_example1][1].lower())
45004500
assert re.match(".*octopus.*not.*uuid4.*", error_yaml[method_example1][2].lower())
45014501
assert re.match(".*method.*not found.*", error_yaml[method_example2][0].lower())
4502+
4503+
4504+
def test_proto_build_skip_context_analysis():
4505+
"""Test that Proto.build works with skip_context_analysis=True."""
4506+
fdp = make_file_pb2(
4507+
name="my_proto.proto",
4508+
package="google.example.v1",
4509+
messages=(make_message_pb2(name="MyMessage"),),
4510+
)
4511+
4512+
# When skip_context_analysis is True, it should still return a Proto object
4513+
# but skip the context analysis phase (resolving collisions etc which happens in with_context).
4514+
# Since we can't easily check internal state of "naive" vs "context-aware" without
4515+
# relying on implementation details, we at least ensure it runs and returns a Proto.
4516+
4517+
proto = api.Proto.build(
4518+
fdp, file_to_generate=True, naming=make_naming(), skip_context_analysis=True
4519+
)
4520+
4521+
assert isinstance(proto, api.Proto)
4522+
assert "google.example.v1.MyMessage" in proto.messages
4523+
assert proto.file_to_generate is True
4524+
4525+
4526+
def test_api_build_uses_skip_context_analysis():
4527+
"""Test that API.build calls Proto.build with skip_context_analysis=True in the first pass."""
4528+
4529+
fd = make_file_pb2(
4530+
name="test.proto",
4531+
package="google.example.v1",
4532+
messages=(make_message_pb2(name="Msg"),),
4533+
)
4534+
4535+
with mock.patch.object(
4536+
api.Proto, "build", side_effect=api.Proto.build
4537+
) as mock_proto_build:
4538+
api.API.build([fd], package="google.example.v1")
4539+
4540+
# API.build makes 2 passes (plus maybe more for other things).
4541+
# The first pass should have skip_context_analysis=True.
4542+
4543+
# Gather all calls
4544+
calls = mock_proto_build.call_args_list
4545+
4546+
# There should be at least 2 calls for our file (Pass 1 and Pass 2).
4547+
# We look for the one with skip_context_analysis=True.
4548+
4549+
found_skip = False
4550+
for call in calls:
4551+
# call.kwargs contains arguments
4552+
if call.kwargs.get("skip_context_analysis") is True:
4553+
found_skip = True
4554+
# Also verify load_services is False as per current implementation of Pass 1
4555+
assert call.kwargs.get("load_services") is False
4556+
break
4557+
4558+
assert found_skip, "Proto.build was not called with skip_context_analysis=True"
4559+
4560+
4561+
def test_proto_builder_skip_context_analysis_property():
4562+
"""Test that _ProtoBuilder sets the skip_context_analysis property correctly."""
4563+
fdp = descriptor_pb2.FileDescriptorProto(
4564+
name="my_proto_file.proto",
4565+
package="google.example.v1",
4566+
)
4567+
4568+
builder = api._ProtoBuilder(
4569+
fdp,
4570+
file_to_generate=True,
4571+
naming=make_naming(),
4572+
skip_context_analysis=True,
4573+
)
4574+
4575+
assert builder.skip_context_analysis is True
4576+
4577+
# Verify that .proto property returns the naive proto when skip_context_analysis is True
4578+
# We can check if the return value is the same as the 'naive' one constructed inside.
4579+
# But since we can't access 'naive' local variable, we verify behavior.
4580+
4581+
proto = builder.proto
4582+
assert isinstance(proto, api.Proto)

0 commit comments

Comments
 (0)