Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix resource path args for paths with =** #1089

Merged
merged 3 commits into from Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion gapic/samplegen/samplegen.py
Expand Up @@ -110,7 +110,7 @@ class TransformedRequest:

# Resource patterns look something like
# kingdom/{kingdom}/phylum/{phylum}/class/{class}
RESOURCE_RE = re.compile(r"\{([^}/]+)\}")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex seemed to be serving the same purpose as the one in wrappers.py

RESOURCE_RE = wrappers.MessageType.PATH_ARG_RE

@classmethod
def build(
Expand Down Expand Up @@ -198,6 +198,11 @@ def build(
raise types.NoSuchResourcePattern(
f"Resource {resource_typestr} has no pattern with params: {attr_name_str}"
)
# This re-writes
# patterns like: 'projects/{project}/metricDescriptors/{metric_descriptor=**}'
# to 'projects/{project}/metricDescriptors/{metric_descriptor}
# so it can be used in sample code as an f-string.
pattern = cls.RESOURCE_RE.sub(r"{\g<1>}", pattern)

return cls(base=base, body=attrs, single=None, pattern=pattern,)

Expand Down
3 changes: 2 additions & 1 deletion gapic/schema/wrappers.py
Expand Up @@ -317,7 +317,8 @@ def __getattr__(self, name):
class MessageType:
"""Description of a message (defined with the ``message`` keyword)."""
# Class attributes
PATH_ARG_RE = re.compile(r'\{([a-zA-Z0-9_-]+)\}')
# https://google.aip.dev/122
PATH_ARG_RE = re.compile(r'\{([a-zA-Z0-9_\-]+)(?:=\*\*)?\}')

# Instance attributes
message_pb: descriptor_pb2.DescriptorProto
Expand Down
Expand Up @@ -38,8 +38,13 @@ async def sample_list_resources():
part_id = "part_id_value"
parent = f"items/{item_id}/parts/{part_id}"

item_id = "item_id_value"
part_id = "part_id_value"
resource_with_wildcard = f"items/{item_id}/parts/{part_id}"

request = mollusca_v1.ListResourcesRequest(
parent=parent,
resource_with_wildcard=resource_with_wildcard,
)

# Make the request
Expand Down
Expand Up @@ -38,8 +38,13 @@ def sample_list_resources():
part_id = "part_id_value"
parent = f"items/{item_id}/parts/{part_id}"

item_id = "item_id_value"
part_id = "part_id_value"
resource_with_wildcard = f"items/{item_id}/parts/{part_id}"

request = mollusca_v1.ListResourcesRequest(
parent=parent,
resource_with_wildcard=resource_with_wildcard,
)

# Make the request
Expand Down
19 changes: 16 additions & 3 deletions tests/snippetgen/snippets.proto
Expand Up @@ -67,9 +67,15 @@ message ListResourcesRequest {
(google.api.resource_reference) = {
type: "snippets.example.com/Resource"
}];

string resource_with_wildcard = 2 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
type: "snippets.example.com/ResourceWithWildcardSegment"
}];

int32 page_size = 2;
string page_token = 3;
int32 page_size = 3;
string page_token = 4;
}

message ListResourcesResponse {
Expand All @@ -91,10 +97,17 @@ message Resource {
pattern: "items/{item_id}/parts/{part_id}"
};
string name = 1;
}


message ResourceWithWildcardSegment {
option (google.api.resource) = {
type: "snippets.example.com/ResourceWithWildcardSegment"
pattern: "items/{item_id}/parts/{part_id=**}"
};
string name = 1;
}


message MessageWithNesting {
message NestedMessage {
string required_string = 1 [(google.api.field_behavior) = REQUIRED];
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/schema/wrappers/test_message.py
Expand Up @@ -201,6 +201,27 @@ def test_resource_path():
assert message.resource_type == "Class"


def test_resource_path_with_wildcard():
options = descriptor_pb2.MessageOptions()
resource = options.Extensions[resource_pb2.resource]
resource.pattern.append(
"kingdoms/{kingdom}/phyla/{phylum}/classes/{klass=**}")
resource.pattern.append(
"kingdoms/{kingdom}/divisions/{division}/classes/{klass}")
resource.type = "taxonomy.biology.com/Class"
message = make_message('Squid', options=options)

assert message.resource_path == "kingdoms/{kingdom}/phyla/{phylum}/classes/{klass=**}"
assert message.resource_path_args == ["kingdom", "phylum", "klass"]
assert message.resource_type == "Class"
assert re.match(message.path_regex_str,
"kingdoms/my-kingdom/phyla/my-phylum/classes/my-klass")
assert re.match(message.path_regex_str,
"kingdoms/my-kingdom/phyla/my-phylum/classes/my-klass/additional-segment")
assert re.match(message.path_regex_str,
"kingdoms/my-kingdom/phyla/my-phylum/classes/") is None


def test_parse_resource_path():
options = descriptor_pb2.MessageOptions()
resource = options.Extensions[resource_pb2.resource]
Expand Down