Skip to content

Commit

Permalink
feat(snippetgen): turn resource path strings into f-strings (#1012)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
busunkim96 authored Nov 5, 2021
1 parent 905c0fe commit a110e1d
Show file tree
Hide file tree
Showing 91 changed files with 529 additions and 118 deletions.
80 changes: 57 additions & 23 deletions gapic/samplegen/samplegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class TransformedRequest:
def build(
cls,
request_type: wrappers.MessageType,
api_schema,
api_schema: api.API,
base: str,
attrs: List[AttributeRequestSetup],
is_resource_request: bool,
Expand Down Expand Up @@ -163,25 +163,22 @@ def build(
#
# It's a precondition that the base field is
# a valid field of the request message type.
resource_typestr = (
request_type.fields[base]
.options.Extensions[resource_pb2.resource_reference]
.type
)
resource_reference = request_type.fields[base].options.Extensions[resource_pb2.resource_reference]
resource_typestr = resource_reference.type or resource_reference.child_type

resource_message_descriptor = next(
(
msg.options.Extensions[resource_pb2.resource]
for msg in api_schema.messages.values()
if msg.options.Extensions[resource_pb2.resource].type
== resource_typestr
),
None,
)
if not resource_message_descriptor:
resource_message = None
for service in api_schema.services.values():
resource_message = service.resource_messages_dict.get(
resource_typestr)
if resource_message is not None:
break

if resource_message is None:
raise types.NoSuchResource(
f"No message exists for resource: {resource_typestr}"
f"No message exists for resource: {resource_typestr}",
)
resource_message_descriptor = resource_message.options.Extensions[
resource_pb2.resource]

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


def _generate_resource_path_request_object(field_name: str, message: wrappers.MessageType) -> List[Dict[str, str]]:
"""Given a message that represents a resource, generate request objects that
populate the resource path args.
Args:
field_name (str): The name of the field.
message (wrappers.MessageType): The message the field belongs to.
Returns:
List[Dict[str, str]]: A list of dicts that can be turned into TransformedRequests.
"""
request = []

# Look for specific field names to substitute more realistic values
special_values_dict = {
"project": '"my-project-id"',
"location": '"us-central1"'
}

for resource_path_arg in message.resource_path_args:
value = special_values_dict.get(
resource_path_arg, f'"{resource_path_arg}_value"')
request.append({
# See TransformedRequest.build() for how 'field' is parsed
"field": f"{field_name}%{resource_path_arg}",
"value": value,
})

return request


def generate_request_object(api_schema: api.API, service: wrappers.Service, message: wrappers.MessageType, field_name_prefix: str = ""):
"""Generate dummy input for a given message.
Expand Down Expand Up @@ -972,12 +1000,18 @@ def generate_request_object(api_schema: api.API, service: wrappers.Service, mess

# TODO(busunkim): Properly handle map fields
if field.is_primitive:
placeholder_value = field.mock_value_original_type
# If this field identifies a resource use the resource path
if service.resource_messages_dict.get(field.resource_reference):
placeholder_value = service.resource_messages_dict[
field.resource_reference].resource_path
request.append({"field": field_name, "value": placeholder_value})
resource_reference_message = service.resource_messages_dict.get(
field.resource_reference)
# Some resource patterns have no resource_path_args
# https://github.com/googleapis/gapic-generator-python/issues/701
if resource_reference_message and resource_reference_message.resource_path_args:
request += _generate_resource_path_request_object(
field_name,
resource_reference_message
)
else:
request.append(
{"field": field_name, "value": field.mock_value_original_type})
elif field.enum:
# Choose the last enum value in the list since index 0 is often "unspecified"
request.append(
Expand Down
5 changes: 3 additions & 2 deletions gapic/templates/examples/feature_fragments.j2
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,10 @@ client = {{ module_name }}.{{ client_name }}()
{# This is a resource-name patterned lookup parameter #}
{% with formals = [] %}
{% for attr in parameter_block.body %}
{% do formals.append("%s=%s"|format(attr.field, attr.input_parameter or attr.value)) %}
{{ attr.field }} = {{ attr.input_parameter or attr.value }}
{% endfor %}
{{ parameter_block.base }} = "{{parameter_block.pattern }}".format({{ formals|join(", ") }})
{{ parameter_block.base }} = f"{{parameter_block.pattern }}"

{% endwith %}
{% else %}{# End resource name construction #}
{{ parameter_block.base }} = {{ module_name }}.{{ request_type.get_field(parameter_block.base).type.name }}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def sample_batch_get_assets_history():

# Initialize request argument(s)
request = asset_v1.BatchGetAssetsHistoryRequest(
parent="*",
parent="parent_value",
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def sample_batch_get_assets_history():

# Initialize request argument(s)
request = asset_v1.BatchGetAssetsHistoryRequest(
parent="*",
parent="parent_value",
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async def sample_delete_feed():
client = asset_v1.AssetServiceAsyncClient()

# Initialize request argument(s)
project = "my-project-id"
feed = "feed_value"
name = f"projects/{project}/feeds/{feed}"

request = asset_v1.DeleteFeedRequest(
name="projects/{project}/feeds/{feed}",
name=name,
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ def sample_delete_feed():
client = asset_v1.AssetServiceClient()

# Initialize request argument(s)
project = "my-project-id"
feed = "feed_value"
name = f"projects/{project}/feeds/{feed}"

request = asset_v1.DeleteFeedRequest(
name="projects/{project}/feeds/{feed}",
name=name,
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async def sample_export_assets():
output_config.gcs_destination.uri = "uri_value"

request = asset_v1.ExportAssetsRequest(
parent="*",
parent="parent_value",
output_config=output_config,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def sample_export_assets():
output_config.gcs_destination.uri = "uri_value"

request = asset_v1.ExportAssetsRequest(
parent="*",
parent="parent_value",
output_config=output_config,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async def sample_get_feed():
client = asset_v1.AssetServiceAsyncClient()

# Initialize request argument(s)
project = "my-project-id"
feed = "feed_value"
name = f"projects/{project}/feeds/{feed}"

request = asset_v1.GetFeedRequest(
name="projects/{project}/feeds/{feed}",
name=name,
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ def sample_get_feed():
client = asset_v1.AssetServiceClient()

# Initialize request argument(s)
project = "my-project-id"
feed = "feed_value"
name = f"projects/{project}/feeds/{feed}"

request = asset_v1.GetFeedRequest(
name="projects/{project}/feeds/{feed}",
name=name,
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def sample_list_assets():

# Initialize request argument(s)
request = asset_v1.ListAssetsRequest(
parent="*",
parent="parent_value",
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def sample_list_assets():

# Initialize request argument(s)
request = asset_v1.ListAssetsRequest(
parent="*",
parent="parent_value",
)

# Make the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async def sample_generate_access_token():
client = credentials_v1.IAMCredentialsAsyncClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.GenerateAccessTokenRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
scope=['scope_value_1', 'scope_value_2'],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ def sample_generate_access_token():
client = credentials_v1.IAMCredentialsClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.GenerateAccessTokenRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
scope=['scope_value_1', 'scope_value_2'],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async def sample_generate_id_token():
client = credentials_v1.IAMCredentialsAsyncClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.GenerateIdTokenRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
audience="audience_value",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ def sample_generate_id_token():
client = credentials_v1.IAMCredentialsClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.GenerateIdTokenRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
audience="audience_value",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async def sample_sign_blob():
client = credentials_v1.IAMCredentialsAsyncClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.SignBlobRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
payload=b'payload_blob',
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ def sample_sign_blob():
client = credentials_v1.IAMCredentialsClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.SignBlobRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
payload=b'payload_blob',
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async def sample_sign_jwt():
client = credentials_v1.IAMCredentialsAsyncClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.SignJwtRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
payload="payload_value",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ def sample_sign_jwt():
client = credentials_v1.IAMCredentialsClient()

# Initialize request argument(s)
project = "my-project-id"
service_account = "service_account_value"
name = f"projects/{project}/serviceAccounts/{service_account}"

request = credentials_v1.SignJwtRequest(
name="projects/{project}/serviceAccounts/{service_account}",
name=name,
payload="payload_value",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ async def sample_create_bucket():
client = logging_v2.ConfigServiceV2AsyncClient()

# Initialize request argument(s)
project = "my-project-id"
location = "us-central1"
bucket = "bucket_value"
parent = f"projects/{project}/locations/{location}/buckets/{bucket}"

request = logging_v2.CreateBucketRequest(
parent="projects/{project}/locations/{location}/buckets/{bucket}",
parent=parent,
bucket_id="bucket_id_value",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ def sample_create_bucket():
client = logging_v2.ConfigServiceV2Client()

# Initialize request argument(s)
project = "my-project-id"
location = "us-central1"
bucket = "bucket_value"
parent = f"projects/{project}/locations/{location}/buckets/{bucket}"

request = logging_v2.CreateBucketRequest(
parent="projects/{project}/locations/{location}/buckets/{bucket}",
parent=parent,
bucket_id="bucket_id_value",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,16 @@ async def sample_create_exclusion():
client = logging_v2.ConfigServiceV2AsyncClient()

# Initialize request argument(s)
project = "my-project-id"
exclusion = "exclusion_value"
parent = f"projects/{project}/exclusions/{exclusion}"

exclusion = logging_v2.LogExclusion()
exclusion.name = "name_value"
exclusion.filter = "filter_value"

request = logging_v2.CreateExclusionRequest(
parent="projects/{project}/exclusions/{exclusion}",
parent=parent,
exclusion=exclusion,
)

Expand Down
Loading

0 comments on commit a110e1d

Please sign in to comment.