Skip to content

Commit 52bfd6d

Browse files
authored
fix: resource messages in method response types generate helpers (googleapis#629)
Some resource messages are only referenced in method responses, either directly (the method returns a resource) or indirectly (the resource is a field for some other message). These response-resources now generate helper methods in client classes. Contains a minor formatting fix in the generated output, a minor fix in an error message, and a tweak to nox.py to aid interactive debugging.
1 parent 57c0423 commit 52bfd6d

5 files changed

Lines changed: 71 additions & 19 deletions

File tree

gapic/schema/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ def __init__(
460460
else:
461461
raise TypeError(
462462
f"Unknown type referenced in "
463-
"{self.file_descriptor.name}: '{key}'"
463+
f"{self.file_descriptor.name}: '{key}'"
464464
)
465465

466466
# Only generate the service if this is a target file to be generated.

gapic/schema/wrappers.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,7 @@ def names(self) -> FrozenSet[str]:
10121012
@utils.cached_property
10131013
def resource_messages(self) -> FrozenSet[MessageType]:
10141014
"""Returns all the resource message types used in all
1015-
request fields in the service."""
1015+
request and response fields in the service."""
10161016
def gen_resources(message):
10171017
if message.resource_path:
10181018
yield message
@@ -1022,9 +1022,14 @@ def gen_resources(message):
10221022
yield type_
10231023

10241024
return frozenset(
1025-
resource_msg
1025+
msg
10261026
for method in self.methods.values()
1027-
for resource_msg in gen_resources(method.input)
1027+
for msg in chain(
1028+
gen_resources(method.input),
1029+
gen_resources(
1030+
method.lro.response_type if method.lro else method.output
1031+
),
1032+
)
10281033
)
10291034

10301035
@utils.cached_property

gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
137137
"""Parse a {{ message.resource_type|snake_case }} path into its component segments."""
138138
m = re.match(r"{{ message.path_regex_str }}", path)
139139
return m.groupdict() if m else {}
140+
140141
{% endfor %} {# resources #}
141142
{% for resource_msg in service.common_resources|sort(attribute="type_name") -%}
142143
@staticmethod

noxfile.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,18 @@ def unit(session):
3737

3838
session.run(
3939
"py.test",
40-
"-vv",
41-
"-n=auto",
42-
"--cov=gapic",
43-
"--cov-config=.coveragerc",
44-
"--cov-report=term",
45-
"--cov-report=html",
46-
*(session.posargs or [path.join("tests", "unit")]),
40+
*(
41+
session.posargs
42+
or [
43+
"-vv",
44+
"-n=auto",
45+
"--cov=gapic",
46+
"--cov-config=.coveragerc",
47+
"--cov-report=term",
48+
"--cov-report=html",
49+
path.join("tests", "unit"),
50+
]
51+
),
4752
)
4853

4954

tests/unit/schema/wrappers/test_service.py

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,24 @@
3232
make_service_with_method_options,
3333
)
3434

35+
################################
36+
# Helper Functions
37+
################################
38+
39+
40+
def make_resource_opts(*args):
41+
# Resources are labeled via an options extension
42+
opts = descriptor_pb2.MessageOptions()
43+
opts.Extensions[resource_pb2.resource].pattern.append(
44+
"/".join("{{{arg}}}/{arg}" for arg in args)
45+
)
46+
return opts
47+
48+
49+
################################
50+
# End Helper Functions
51+
################################
52+
3553

3654
def test_service_properties():
3755
service = make_service(name='ThingDoer')
@@ -162,14 +180,6 @@ def test_module_name():
162180

163181

164182
def test_resource_messages():
165-
# Resources are labeled via an options extension
166-
def make_resource_opts(*args):
167-
opts = descriptor_pb2.MessageOptions()
168-
opts.Extensions[resource_pb2.resource].pattern.append(
169-
"/".join("{{{arg}}}/{arg}" for arg in args)
170-
)
171-
return opts
172-
173183
# Regular, top level resource
174184
squid_resource = make_message("Squid", options=make_resource_opts("squid"))
175185
squid_request = make_message(
@@ -336,3 +346,34 @@ def test_common_resource_patterns():
336346
assert species_msg.resource_type == "Species"
337347
assert species_msg.resource_path_args == ["family", "genus", "species"]
338348
assert species_msg.path_regex_str == '^families/(?P<family>.+?)/genera/(?P<genus>.+?)/species/(?P<species>.+?)$'
349+
350+
351+
def test_resource_response():
352+
# Top level response resource
353+
squid_resource = make_message("Squid", options=make_resource_opts("squid"))
354+
squid_request = make_message("CreateSquidRequest")
355+
356+
# Nested response resource
357+
clam_resource = make_message("Clam", options=make_resource_opts("clam"))
358+
clam_response = make_message(
359+
"CreateClamResponse",
360+
fields=(
361+
make_field('clam', message=clam_resource),
362+
),
363+
)
364+
clam_request = make_message("CreateClamRequest")
365+
366+
mollusc_service = make_service(
367+
"MolluscService",
368+
methods=(
369+
make_method(f"{request.name}", request, response)
370+
for request, response in (
371+
(squid_request, squid_resource),
372+
(clam_request, clam_response),
373+
)
374+
),
375+
)
376+
377+
expected = {squid_resource, clam_resource}
378+
actual = mollusc_service.resource_messages
379+
assert expected == actual

0 commit comments

Comments
 (0)