Skip to content

Commit a110e1d

Browse files
authored
feat(snippetgen): turn resource path strings into f-strings (#1012)
Fixes #965. Uses the already-existing resource path logic for autogen snippets. Previous: ```py # Initialize request argument(s) request = asset_v1.DeleteFeedRequest( name="projects/{project}/feeds/{feed}", ) ``` Now: ```py # Initialize request argument(s) project = "my-project-id" feed = "feed_value" name = f"projects/{project}/feeds/{feed}" request = asset_v1.DeleteFeedRequest( name=name, ) ``` Note: The logic may result in multiple variables with the same name (it doesn't happen for any of the golden APIs, but might for an API with more required fields).
1 parent 905c0fe commit a110e1d

File tree

91 files changed

+529
-118
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+529
-118
lines changed

gapic/samplegen/samplegen.py

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class TransformedRequest:
116116
def build(
117117
cls,
118118
request_type: wrappers.MessageType,
119-
api_schema,
119+
api_schema: api.API,
120120
base: str,
121121
attrs: List[AttributeRequestSetup],
122122
is_resource_request: bool,
@@ -163,25 +163,22 @@ def build(
163163
#
164164
# It's a precondition that the base field is
165165
# a valid field of the request message type.
166-
resource_typestr = (
167-
request_type.fields[base]
168-
.options.Extensions[resource_pb2.resource_reference]
169-
.type
170-
)
166+
resource_reference = request_type.fields[base].options.Extensions[resource_pb2.resource_reference]
167+
resource_typestr = resource_reference.type or resource_reference.child_type
171168

172-
resource_message_descriptor = next(
173-
(
174-
msg.options.Extensions[resource_pb2.resource]
175-
for msg in api_schema.messages.values()
176-
if msg.options.Extensions[resource_pb2.resource].type
177-
== resource_typestr
178-
),
179-
None,
180-
)
181-
if not resource_message_descriptor:
169+
resource_message = None
170+
for service in api_schema.services.values():
171+
resource_message = service.resource_messages_dict.get(
172+
resource_typestr)
173+
if resource_message is not None:
174+
break
175+
176+
if resource_message is None:
182177
raise types.NoSuchResource(
183-
f"No message exists for resource: {resource_typestr}"
178+
f"No message exists for resource: {resource_typestr}",
184179
)
180+
resource_message_descriptor = resource_message.options.Extensions[
181+
resource_pb2.resource]
185182

186183
# The field is only ever empty for singleton attributes.
187184
attr_names: List[str] = [a.field for a in attrs] # type: ignore
@@ -944,6 +941,37 @@ def parse_handwritten_specs(sample_configs: Sequence[str]) -> Generator[Dict[str
944941
yield spec
945942

946943

944+
def _generate_resource_path_request_object(field_name: str, message: wrappers.MessageType) -> List[Dict[str, str]]:
945+
"""Given a message that represents a resource, generate request objects that
946+
populate the resource path args.
947+
948+
Args:
949+
field_name (str): The name of the field.
950+
message (wrappers.MessageType): The message the field belongs to.
951+
952+
Returns:
953+
List[Dict[str, str]]: A list of dicts that can be turned into TransformedRequests.
954+
"""
955+
request = []
956+
957+
# Look for specific field names to substitute more realistic values
958+
special_values_dict = {
959+
"project": '"my-project-id"',
960+
"location": '"us-central1"'
961+
}
962+
963+
for resource_path_arg in message.resource_path_args:
964+
value = special_values_dict.get(
965+
resource_path_arg, f'"{resource_path_arg}_value"')
966+
request.append({
967+
# See TransformedRequest.build() for how 'field' is parsed
968+
"field": f"{field_name}%{resource_path_arg}",
969+
"value": value,
970+
})
971+
972+
return request
973+
974+
947975
def generate_request_object(api_schema: api.API, service: wrappers.Service, message: wrappers.MessageType, field_name_prefix: str = ""):
948976
"""Generate dummy input for a given message.
949977
@@ -972,12 +1000,18 @@ def generate_request_object(api_schema: api.API, service: wrappers.Service, mess
9721000

9731001
# TODO(busunkim): Properly handle map fields
9741002
if field.is_primitive:
975-
placeholder_value = field.mock_value_original_type
976-
# If this field identifies a resource use the resource path
977-
if service.resource_messages_dict.get(field.resource_reference):
978-
placeholder_value = service.resource_messages_dict[
979-
field.resource_reference].resource_path
980-
request.append({"field": field_name, "value": placeholder_value})
1003+
resource_reference_message = service.resource_messages_dict.get(
1004+
field.resource_reference)
1005+
# Some resource patterns have no resource_path_args
1006+
# https://github.com/googleapis/gapic-generator-python/issues/701
1007+
if resource_reference_message and resource_reference_message.resource_path_args:
1008+
request += _generate_resource_path_request_object(
1009+
field_name,
1010+
resource_reference_message
1011+
)
1012+
else:
1013+
request.append(
1014+
{"field": field_name, "value": field.mock_value_original_type})
9811015
elif field.enum:
9821016
# Choose the last enum value in the list since index 0 is often "unspecified"
9831017
request.append(

gapic/templates/examples/feature_fragments.j2

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,10 @@ client = {{ module_name }}.{{ client_name }}()
160160
{# This is a resource-name patterned lookup parameter #}
161161
{% with formals = [] %}
162162
{% for attr in parameter_block.body %}
163-
{% do formals.append("%s=%s"|format(attr.field, attr.input_parameter or attr.value)) %}
163+
{{ attr.field }} = {{ attr.input_parameter or attr.value }}
164164
{% endfor %}
165-
{{ parameter_block.base }} = "{{parameter_block.pattern }}".format({{ formals|join(", ") }})
165+
{{ parameter_block.base }} = f"{{parameter_block.pattern }}"
166+
166167
{% endwith %}
167168
{% else %}{# End resource name construction #}
168169
{{ parameter_block.base }} = {{ module_name }}.{{ request_type.get_field(parameter_block.base).type.name }}()

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_batch_get_assets_history_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ async def sample_batch_get_assets_history():
3535

3636
# Initialize request argument(s)
3737
request = asset_v1.BatchGetAssetsHistoryRequest(
38-
parent="*",
38+
parent="parent_value",
3939
)
4040

4141
# Make the request

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_batch_get_assets_history_sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def sample_batch_get_assets_history():
3535

3636
# Initialize request argument(s)
3737
request = asset_v1.BatchGetAssetsHistoryRequest(
38-
parent="*",
38+
parent="parent_value",
3939
)
4040

4141
# Make the request

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_delete_feed_async.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ async def sample_delete_feed():
3434
client = asset_v1.AssetServiceAsyncClient()
3535

3636
# Initialize request argument(s)
37+
project = "my-project-id"
38+
feed = "feed_value"
39+
name = f"projects/{project}/feeds/{feed}"
40+
3741
request = asset_v1.DeleteFeedRequest(
38-
name="projects/{project}/feeds/{feed}",
42+
name=name,
3943
)
4044

4145
# Make the request

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_delete_feed_sync.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ def sample_delete_feed():
3434
client = asset_v1.AssetServiceClient()
3535

3636
# Initialize request argument(s)
37+
project = "my-project-id"
38+
feed = "feed_value"
39+
name = f"projects/{project}/feeds/{feed}"
40+
3741
request = asset_v1.DeleteFeedRequest(
38-
name="projects/{project}/feeds/{feed}",
42+
name=name,
3943
)
4044

4145
# Make the request

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_export_assets_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ async def sample_export_assets():
3838
output_config.gcs_destination.uri = "uri_value"
3939

4040
request = asset_v1.ExportAssetsRequest(
41-
parent="*",
41+
parent="parent_value",
4242
output_config=output_config,
4343
)
4444

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_export_assets_sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def sample_export_assets():
3838
output_config.gcs_destination.uri = "uri_value"
3939

4040
request = asset_v1.ExportAssetsRequest(
41-
parent="*",
41+
parent="parent_value",
4242
output_config=output_config,
4343
)
4444

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_get_feed_async.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ async def sample_get_feed():
3434
client = asset_v1.AssetServiceAsyncClient()
3535

3636
# Initialize request argument(s)
37+
project = "my-project-id"
38+
feed = "feed_value"
39+
name = f"projects/{project}/feeds/{feed}"
40+
3741
request = asset_v1.GetFeedRequest(
38-
name="projects/{project}/feeds/{feed}",
42+
name=name,
3943
)
4044

4145
# Make the request

tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_get_feed_sync.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ def sample_get_feed():
3434
client = asset_v1.AssetServiceClient()
3535

3636
# Initialize request argument(s)
37+
project = "my-project-id"
38+
feed = "feed_value"
39+
name = f"projects/{project}/feeds/{feed}"
40+
3741
request = asset_v1.GetFeedRequest(
38-
name="projects/{project}/feeds/{feed}",
42+
name=name,
3943
)
4044

4145
# Make the request

0 commit comments

Comments
 (0)