Skip to content

Commit 5531795

Browse files
authored
fix(snippetgen): don't create duplicate requests for required oneofs (googleapis#1088)
Some APIs mark every field in a oneof as "required" to express that the oneof itself is required. https://github.com/googleapis/googleapis/blob/55726d62556966c095a096aed1ffda5da231f36d/google/cloud/channel/v1/service.proto#L1057-L1069 ```proto // Request message for [CloudChannelService.ImportCustomer][google.cloud.channel.v1.CloudChannelService.ImportCustomer] message ImportCustomerRequest { // Specifies the identity of the transfer customer. // A customer's cloud_identity_id or domain is required to look up the // customer's Cloud Identity. For Team customers, only the cloud_identity_id // option is valid. oneof customer_identity { // Required. Customer domain. string domain = 2 [(google.api.field_behavior) = REQUIRED]; // Required. Customer's Cloud Identity ID string cloud_identity_id = 3 [(google.api.field_behavior) = REQUIRED]; } ... ``` This causes an error in the current logic since two requests are generated for the same field.
1 parent 309cc66 commit 5531795

File tree

4 files changed

+118
-3
lines changed

4 files changed

+118
-3
lines changed

gapic/samplegen/samplegen.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from gapic.schema import wrappers
3131

3232
from collections import defaultdict, namedtuple, ChainMap as chainmap
33-
from typing import Any, ChainMap, Dict, FrozenSet, Generator, List, Mapping, Optional, Tuple, Sequence
33+
from typing import Any, ChainMap, Dict, FrozenSet, Generator, List, Mapping, Optional, Sequence
3434

3535
# There is no library stub file for this module, so ignore it.
3636
from google.api import resource_pb2 # type: ignore
@@ -981,10 +981,16 @@ def generate_request_object(api_schema: api.API, service: wrappers.Service, mess
981981

982982
request_fields: List[wrappers.Field] = []
983983

984-
# Choose the first option for each oneof
984+
# There is no standard syntax to mark a oneof as "required" in protos.
985+
# Assume every oneof is required and pick the first option
986+
# in each oneof.
985987
selected_oneofs: List[wrappers.Field] = [oneof_fields[0]
986988
for oneof_fields in message.oneof_fields().values()]
987-
request_fields = selected_oneofs + message.required_fields
989+
990+
# Don't add required fields if they're also marked as oneof
991+
required_fields = [
992+
field for field in message.required_fields if not field.oneof]
993+
request_fields = selected_oneofs + required_fields
988994

989995
for field in request_fields:
990996
# TransformedRequest expects nested fields to be referenced like
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2020 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
# Generated code. DO NOT EDIT!
17+
#
18+
# Snippet for OneOfMethodRequiredField
19+
# NOTE: This snippet has been automatically generated for illustrative purposes only.
20+
# It may require modifications to work in your environment.
21+
22+
# To install the latest published package dependency, execute the following:
23+
# python3 -m pip install animalia-mollusca
24+
25+
26+
# [START mollusca_generated_mollusca_v1_Snippets_OneOfMethodRequiredField_async]
27+
from animalia import mollusca_v1
28+
29+
30+
async def sample_one_of_method_required_field():
31+
"""Snippet for one_of_method_required_field"""
32+
33+
# Create a client
34+
client = mollusca_v1.SnippetsAsyncClient()
35+
36+
# Initialize request argument(s)
37+
request = mollusca_v1.OneOfRequestWithRequiredField(
38+
my_string="my_string_value",
39+
non_one_of_string="non_one_of_string_value",
40+
)
41+
42+
# Make the request
43+
response = await client.one_of_method_required_field(request=request)
44+
45+
# Handle response
46+
print(response)
47+
48+
# [END mollusca_generated_mollusca_v1_Snippets_OneOfMethodRequiredField_async]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2020 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
# Generated code. DO NOT EDIT!
17+
#
18+
# Snippet for OneOfMethodRequiredField
19+
# NOTE: This snippet has been automatically generated for illustrative purposes only.
20+
# It may require modifications to work in your environment.
21+
22+
# To install the latest published package dependency, execute the following:
23+
# python3 -m pip install animalia-mollusca
24+
25+
26+
# [START mollusca_generated_mollusca_v1_Snippets_OneOfMethodRequiredField_sync]
27+
from animalia import mollusca_v1
28+
29+
30+
def sample_one_of_method_required_field():
31+
"""Snippet for one_of_method_required_field"""
32+
33+
# Create a client
34+
client = mollusca_v1.SnippetsClient()
35+
36+
# Initialize request argument(s)
37+
request = mollusca_v1.OneOfRequestWithRequiredField(
38+
my_string="my_string_value",
39+
non_one_of_string="non_one_of_string_value",
40+
)
41+
42+
# Make the request
43+
response = client.one_of_method_required_field(request=request)
44+
45+
# Handle response
46+
print(response)
47+
48+
# [END mollusca_generated_mollusca_v1_Snippets_OneOfMethodRequiredField_sync]

tests/snippetgen/snippets.proto

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ service Snippets {
5555
rpc MethodBidiStreaming(stream SignatureRequestOneRequiredField) returns (stream Response);
5656

5757
rpc OneOfMethod(OneOfRequest) returns (Response);
58+
59+
rpc OneOfMethodRequiredField(OneOfRequestWithRequiredField) returns (Response);
5860
}
5961

6062
enum Enum {
@@ -149,3 +151,14 @@ message OneOfRequest {
149151
int32 my_number = 3;
150152
}
151153
}
154+
155+
156+
message OneOfRequestWithRequiredField {
157+
string non_one_of_string = 1 [(google.api.field_behavior) = REQUIRED];
158+
159+
// Some APIs mark every field in a "required" oneof as required
160+
oneof my_one_of {
161+
string my_string = 2 [(google.api.field_behavior) = REQUIRED];
162+
int32 my_number = 3 [(google.api.field_behavior) = REQUIRED];
163+
}
164+
}

0 commit comments

Comments
 (0)