From 6b1f06b07e1dc26c30df2a6656f3fa268f48dd76 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Tue, 4 May 2021 17:18:23 +0000 Subject: [PATCH] feat: add async samples --- gapic/samplegen/samplegen.py | 20 +- gapic/templates/examples/feature_fragments.j2 | 17 +- gapic/templates/examples/sample.py.j2 | 6 +- ...llusca_v1_snippets_list_resources_async.py | 45 +++++ ...llusca_v1_snippets_list_resources_sync.py} | 4 +- ...v1_snippets_method_bidi_streaming_async.py | 45 +++++ ...v1_snippets_method_bidi_streaming_sync.py} | 4 +- ...v1_snippets_method_lro_signatures_async.py | 48 +++++ ...v1_snippets_method_lro_signatures_sync.py} | 4 +- ..._v1_snippets_method_one_signature_async.py | 46 +++++ ..._v1_snippets_method_one_signature_sync.py} | 4 +- ..._snippets_method_server_streaming_async.py | 45 +++++ ..._snippets_method_server_streaming_sync.py} | 4 +- .../golden_snippets/sample_basic_async.py | 55 ++++++ tests/unit/samplegen/test_integration.py | 73 +++++++ tests/unit/samplegen/test_samplegen.py | 16 +- tests/unit/samplegen/test_template.py | 183 ++++++++++++++++-- 17 files changed, 578 insertions(+), 41 deletions(-) create mode 100644 tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_async.py rename tests/snippetgen/goldens/{mollusca_generated_mollusca_v1_snippets_list_resources_grpc.py => mollusca_generated_mollusca_v1_snippets_list_resources_sync.py} (91%) create mode 100644 tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_async.py rename tests/snippetgen/goldens/{mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_grpc.py => mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_sync.py} (98%) create mode 100644 tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_async.py rename tests/snippetgen/goldens/{mollusca_generated_mollusca_v1_snippets_method_lro_signatures_grpc.py => mollusca_generated_mollusca_v1_snippets_method_lro_signatures_sync.py} (98%) create mode 100644 tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_async.py rename tests/snippetgen/goldens/{mollusca_generated_mollusca_v1_snippets_method_one_signature_grpc.py => mollusca_generated_mollusca_v1_snippets_method_one_signature_sync.py} (98%) create mode 100644 tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_async.py rename tests/snippetgen/goldens/{mollusca_generated_mollusca_v1_snippets_method_server_streaming_grpc.py => mollusca_generated_mollusca_v1_snippets_method_server_streaming_sync.py} (98%) create mode 100644 tests/unit/samplegen/golden_snippets/sample_basic_async.py diff --git a/gapic/samplegen/samplegen.py b/gapic/samplegen/samplegen.py index 9cd4987d59..aaea4625ec 100644 --- a/gapic/samplegen/samplegen.py +++ b/gapic/samplegen/samplegen.py @@ -293,7 +293,15 @@ def preprocess_sample(sample, api_schema: api.API, rpc: wrappers.Method): sample["module_name"] = api_schema.naming.versioned_module_name sample["module_namespace"] = api_schema.naming.module_namespace - sample["client_name"] = api_schema.services[sample["service"]].client_name + # Assume the gRPC transport if the transport is not specified + if "transport" not in sample: + sample["transport"] = "grpc" + + if sample["transport"] == "grpc-async": + sample["client_name"] = api_schema.services[sample["service"]].async_client_name + else: + sample["client_name"] = api_schema.services[sample["service"]].client_name + # the type of the request object passed to the rpc e.g, `ListRequest` sample["request_type"] = rpc.input.ident.name @@ -944,10 +952,11 @@ def generate_sample_specs(api_schema: api.API, *, opts) -> Generator[Dict[str, A for service_name, service in gapic_metadata.services.items(): api_short_name = api_schema.services[f"{api_schema.naming.proto_package}.{service_name}"].shortname - for transport_type, client in service.clients.items(): - if transport_type == "grpc-async": - # TODO(busunkim): Enable generation of async samples - continue + for transport_name, client in service.clients.items(): + if transport_name == "grpc-async": + transport_type = "async" + else: + transport_type = "sync" for rpc_name, method_list in client.rpcs.items(): # Region Tag Format: # [{START|END} ${apishortname}_generated_${api}_${apiVersion}_${serviceName}_${rpcName}_{sync|async}_${overloadDisambiguation}] @@ -955,6 +964,7 @@ def generate_sample_specs(api_schema: api.API, *, opts) -> Generator[Dict[str, A spec = { "sample_type": "standalone", "rpc": rpc_name, + "transport": transport_name, "request": [], # response is populated in `preprocess_sample` "service": f"{api_schema.naming.proto_package}.{service_name}", diff --git a/gapic/templates/examples/feature_fragments.j2 b/gapic/templates/examples/feature_fragments.j2 index 2959157a30..1490fd5e40 100644 --- a/gapic/templates/examples/feature_fragments.j2 +++ b/gapic/templates/examples/feature_fragments.j2 @@ -202,8 +202,13 @@ request=request {% endmacro %} -{% macro render_method_call(sample, calling_form, calling_form_enum) %} +{% macro render_method_call(sample, calling_form, calling_form_enum, transport) %} {# Note: this doesn't deal with enums or unions #} +{# LROs return operation objects and paged requests return pager objects #} +{% if transport == "grpc-async" and calling_form not in +[calling_form_enum.LongRunningRequestPromise, calling_form_enum.RequestPagedAll] %} +await{{ " "}} +{%- endif -%} {% if calling_form in [calling_form_enum.RequestStreamingBidi, calling_form_enum.RequestStreamingClient] %} client.{{ sample.rpc|snake_case }}([{{ render_request_params(sample.request.request_list)|trim }}]) @@ -215,7 +220,7 @@ client.{{ sample.rpc|snake_case }}({{ render_request_params_unary(sample.request {# Setting up the method invocation is the responsibility of the caller: #} {# it's just easier to set up client side streaming and other things from outside this macro. #} -{% macro render_calling_form(method_invocation_text, calling_form, calling_form_enum, response_statements ) %} +{% macro render_calling_form(method_invocation_text, calling_form, calling_form_enum, transport, response_statements ) %} # Make the request {% if calling_form == calling_form_enum.Request %} response = {{ method_invocation_text|trim }} @@ -226,13 +231,13 @@ response = {{ method_invocation_text|trim }} {% endfor %} {% elif calling_form == calling_form_enum.RequestPagedAll %} page_result = {{ method_invocation_text|trim }} -for response in page_result: +{% if transport == "grpc-async" %}async {% endif %}for response in page_result: {% for statement in response_statements %} {{ dispatch_statement(statement)|trim }} {% endfor %} {% elif calling_form == calling_form_enum.RequestPaged %} page_result = {{ method_invocation_text|trim }} -for page in page_result.pages(): +{% if transport == "grpc-async" %}async {% endif %}for page in page_result.pages(): for response in page: {% for statement in response_statements %} {{ dispatch_statement(statement)|trim }} @@ -240,7 +245,7 @@ for page in page_result.pages(): {% elif calling_form in [calling_form_enum.RequestStreamingServer, calling_form_enum.RequestStreamingBidi] %} stream = {{ method_invocation_text|trim }} -for response in stream: +{% if transport == "grpc-async" %}async {% endif %}for response in stream: {% for statement in response_statements %} {{ dispatch_statement(statement)|trim }} {% endfor %} @@ -249,7 +254,7 @@ operation = {{ method_invocation_text|trim }} print("Waiting for operation to complete...") -response = operation.result() +response = {% if transport == "grpc-async" %}await {% endif %}operation.result() {% for statement in response_statements %} {{ dispatch_statement(statement)|trim }} {% endfor %} diff --git a/gapic/templates/examples/sample.py.j2 b/gapic/templates/examples/sample.py.j2 index 79614d71a3..54db08ca21 100644 --- a/gapic/templates/examples/sample.py.j2 +++ b/gapic/templates/examples/sample.py.j2 @@ -31,13 +31,13 @@ from {{ sample.module_namespace|join(".") }} import {{ sample.module_name }} {# also need calling form #} -def sample_{{ frags.render_method_name(sample.rpc)|trim }}({{ frags.print_input_params(sample.request)|trim }}): +{% if sample.transport == "grpc-async" %}async {% endif %}def sample_{{ frags.render_method_name(sample.rpc)|trim }}({{ frags.print_input_params(sample.request)|trim }}): """{{ sample.description }}""" {{ frags.render_client_setup(sample.module_name, sample.client_name)|indent }} {{ frags.render_request_setup(sample.request, sample.module_name, sample.request_type)|indent }} - {% with method_call = frags.render_method_call(sample, calling_form, calling_form_enum) %} - {{ frags.render_calling_form(method_call, calling_form, calling_form_enum, sample.response)|indent -}} + {% with method_call = frags.render_method_call(sample, calling_form, calling_form_enum, sample.transport) %} + {{ frags.render_calling_form(method_call, calling_form, calling_form_enum, sample.transport, sample.response)|indent -}} {% endwith %} # [END {{ sample.id }}] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_async.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_async.py new file mode 100644 index 0000000000..72a2f65950 --- /dev/null +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_async.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generated code. DO NOT EDIT! +# +# Snippet for ListResources +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install animalia-mollusca + + +# [START mollusca_generated_mollusca_v1_Snippets_ListResources_async] +from animalia import mollusca_v1 + + +async def sample_list_resources(): + """Snippet for list_resources""" + + # Create a client + client = mollusca_v1.SnippetsAsyncClient() + + # Initialize request argument(s) + request = mollusca_v1.ListResourcesRequest( + ) + + # Make the request + page_result = client.list_resources(request=request) + async for response in page_result: + print("{}".format(response)) + +# [END mollusca_generated_mollusca_v1_Snippets_ListResources_async] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_grpc.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_sync.py similarity index 91% rename from tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_grpc.py rename to tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_sync.py index 1ea032b5d9..e7423eaf3d 100644 --- a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_grpc.py +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_list_resources_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install animalia-mollusca -# [START mollusca_generated_mollusca_v1_Snippets_ListResources_grpc] +# [START mollusca_generated_mollusca_v1_Snippets_ListResources_sync] from animalia import mollusca_v1 @@ -42,4 +42,4 @@ def sample_list_resources(): for response in page_result: print("{}".format(response)) -# [END mollusca_generated_mollusca_v1_Snippets_ListResources_grpc] +# [END mollusca_generated_mollusca_v1_Snippets_ListResources_sync] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_async.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_async.py new file mode 100644 index 0000000000..26ab1b086c --- /dev/null +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_async.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generated code. DO NOT EDIT! +# +# Snippet for MethodBidiStreaming +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install animalia-mollusca + + +# [START mollusca_generated_mollusca_v1_Snippets_MethodBidiStreaming_async] +from animalia import mollusca_v1 + + +async def sample_method_bidi_streaming(): + """Snippet for method_bidi_streaming""" + + # Create a client + client = mollusca_v1.SnippetsAsyncClient() + + # Initialize request argument(s) + request = mollusca_v1.SignatureRequest( + ) + + # Make the request + stream = await client.method_bidi_streaming([]) + async for response in stream: + print("{}".format(response)) + +# [END mollusca_generated_mollusca_v1_Snippets_MethodBidiStreaming_async] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_grpc.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_sync.py similarity index 98% rename from tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_grpc.py rename to tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_sync.py index 1c9be7560f..239eeb7763 100644 --- a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_grpc.py +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_bidi_streaming_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install animalia-mollusca -# [START mollusca_generated_mollusca_v1_Snippets_MethodBidiStreaming_grpc] +# [START mollusca_generated_mollusca_v1_Snippets_MethodBidiStreaming_sync] from animalia import mollusca_v1 @@ -42,4 +42,4 @@ def sample_method_bidi_streaming(): for response in stream: print("{}".format(response)) -# [END mollusca_generated_mollusca_v1_Snippets_MethodBidiStreaming_grpc] +# [END mollusca_generated_mollusca_v1_Snippets_MethodBidiStreaming_sync] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_async.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_async.py new file mode 100644 index 0000000000..3327f9a2b4 --- /dev/null +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_async.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generated code. DO NOT EDIT! +# +# Snippet for MethodLroSignatures +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install animalia-mollusca + + +# [START mollusca_generated_mollusca_v1_Snippets_MethodLroSignatures_async] +from animalia import mollusca_v1 + + +async def sample_method_lro_signatures(): + """Snippet for method_lro_signatures""" + + # Create a client + client = mollusca_v1.SnippetsAsyncClient() + + # Initialize request argument(s) + request = mollusca_v1.SignatureRequest( + ) + + # Make the request + operation = client.method_lro_signatures(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + print("{}".format(response)) + +# [END mollusca_generated_mollusca_v1_Snippets_MethodLroSignatures_async] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_grpc.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_sync.py similarity index 98% rename from tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_grpc.py rename to tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_sync.py index 50974d82b3..af22fb4125 100644 --- a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_grpc.py +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_lro_signatures_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install animalia-mollusca -# [START mollusca_generated_mollusca_v1_Snippets_MethodLroSignatures_grpc] +# [START mollusca_generated_mollusca_v1_Snippets_MethodLroSignatures_sync] from animalia import mollusca_v1 @@ -45,4 +45,4 @@ def sample_method_lro_signatures(): response = operation.result() print("{}".format(response)) -# [END mollusca_generated_mollusca_v1_Snippets_MethodLroSignatures_grpc] +# [END mollusca_generated_mollusca_v1_Snippets_MethodLroSignatures_sync] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_async.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_async.py new file mode 100644 index 0000000000..b8f4629577 --- /dev/null +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_async.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generated code. DO NOT EDIT! +# +# Snippet for MethodOneSignature +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install animalia-mollusca + + +# [START mollusca_generated_mollusca_v1_Snippets_MethodOneSignature_async] +from animalia import mollusca_v1 + + +async def sample_method_one_signature(): + """Snippet for method_one_signature""" + + # Create a client + client = mollusca_v1.SnippetsAsyncClient() + + # Initialize request argument(s) + request = mollusca_v1.SignatureRequest( + ) + + # Make the request + response = await client.method_one_signature(request=request) + + # Handle response + print("{}".format(response)) + +# [END mollusca_generated_mollusca_v1_Snippets_MethodOneSignature_async] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_grpc.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_sync.py similarity index 98% rename from tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_grpc.py rename to tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_sync.py index 9c6192b43f..e8e438f169 100644 --- a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_grpc.py +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_one_signature_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install animalia-mollusca -# [START mollusca_generated_mollusca_v1_Snippets_MethodOneSignature_grpc] +# [START mollusca_generated_mollusca_v1_Snippets_MethodOneSignature_sync] from animalia import mollusca_v1 @@ -43,4 +43,4 @@ def sample_method_one_signature(): # Handle response print("{}".format(response)) -# [END mollusca_generated_mollusca_v1_Snippets_MethodOneSignature_grpc] +# [END mollusca_generated_mollusca_v1_Snippets_MethodOneSignature_sync] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_async.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_async.py new file mode 100644 index 0000000000..753c7666e5 --- /dev/null +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_async.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generated code. DO NOT EDIT! +# +# Snippet for MethodServerStreaming +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install animalia-mollusca + + +# [START mollusca_generated_mollusca_v1_Snippets_MethodServerStreaming_async] +from animalia import mollusca_v1 + + +async def sample_method_server_streaming(): + """Snippet for method_server_streaming""" + + # Create a client + client = mollusca_v1.SnippetsAsyncClient() + + # Initialize request argument(s) + request = mollusca_v1.SignatureRequest( + ) + + # Make the request + stream = await client.method_server_streaming(request=request) + async for response in stream: + print("{}".format(response)) + +# [END mollusca_generated_mollusca_v1_Snippets_MethodServerStreaming_async] diff --git a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_grpc.py b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_sync.py similarity index 98% rename from tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_grpc.py rename to tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_sync.py index 13913a0ed3..339623a2d6 100644 --- a/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_grpc.py +++ b/tests/snippetgen/goldens/mollusca_generated_mollusca_v1_snippets_method_server_streaming_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install animalia-mollusca -# [START mollusca_generated_mollusca_v1_Snippets_MethodServerStreaming_grpc] +# [START mollusca_generated_mollusca_v1_Snippets_MethodServerStreaming_sync] from animalia import mollusca_v1 @@ -42,4 +42,4 @@ def sample_method_server_streaming(): for response in stream: print("{}".format(response)) -# [END mollusca_generated_mollusca_v1_Snippets_MethodServerStreaming_grpc] +# [END mollusca_generated_mollusca_v1_Snippets_MethodServerStreaming_sync] diff --git a/tests/unit/samplegen/golden_snippets/sample_basic_async.py b/tests/unit/samplegen/golden_snippets/sample_basic_async.py new file mode 100644 index 0000000000..5aa99485ad --- /dev/null +++ b/tests/unit/samplegen/golden_snippets/sample_basic_async.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generated code. DO NOT EDIT! +# +# Snippet for Classify +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install molluscs-v1-molluscclient + + +# [START mollusc_classify_sync] +from molluscs.v1 import molluscclient + + +async def sample_classify(video, location): + """Determine the full taxonomy of input mollusc""" + + # Create a client + client = molluscclient.MolluscServiceAsyncClient() + + # Initialize request argument(s) + classify_target = {} + # video = "path/to/mollusc/video.mkv" + with open(video, "rb") as f: + classify_target["video"] = f.read() + + # location = "New Zealand" + classify_target["location_annotation"] = location + + request = molluscclient.molluscs.v1.ClassifyRequest( + classify_target=classify_target, + ) + + # Make the request + response = await client.classify(request=request) + + # Handle response + print("Mollusc is a \"{}\"".format(response.taxonomy)) + +# [END mollusc_classify_sync] diff --git a/tests/unit/samplegen/test_integration.py b/tests/unit/samplegen/test_integration.py index c3a2cb7d2c..1020ec1aab 100644 --- a/tests/unit/samplegen/test_integration.py +++ b/tests/unit/samplegen/test_integration.py @@ -123,6 +123,79 @@ def test_generate_sample_basic(): assert sample_str == golden_snippet("sample_basic.py") +def test_generate_sample_basic_async(): + # Note: the sample integration tests are needfully large + # and difficult to eyeball parse. They are intended to be integration tests + # that catch errors in behavior that is emergent from combining smaller features + # or in features that are sufficiently small and trivial that it doesn't make sense + # to have standalone tests. + + input_type = DummyMessage( + type="REQUEST TYPE", + fields={ + "classify_target": DummyField( + message=DummyMessage( + type="CLASSIFY TYPE", + fields={ + "video": DummyField( + message=DummyMessage(type="VIDEO TYPE"), + ), + "location_annotation": DummyField( + message=DummyMessage(type="LOCATION TYPE"), + ) + }, + ) + ) + }, + ident=DummyIdent(name="molluscs.v1.ClassifyRequest") + ) + + api_naming = naming.NewNaming( + name="MolluscClient", namespace=("molluscs", "v1")) + service = wrappers.Service( + service_pb=namedtuple('service_pb', ['name'])('MolluscService'), + methods={ + "Classify": DummyMethod( + input=input_type, + output=message_factory("$resp.taxonomy"), + flattened_fields={ + "classify_target": DummyField(name="classify_target") + } + ) + }, + visible_resources={}, + ) + + schema = DummyApiSchema( + services={"animalia.mollusca.v1.Mollusc": service}, + naming=api_naming, + ) + + sample = {"service": "animalia.mollusca.v1.Mollusc", + "rpc": "Classify", + "transport": "grpc-async", + "id": "mollusc_classify_sync", + "description": "Determine the full taxonomy of input mollusc", + "request": [ + {"field": "classify_target.video", + "value": "path/to/mollusc/video.mkv", + "input_parameter": "video", + "value_is_file": True}, + {"field": "classify_target.location_annotation", + "value": "New Zealand", + "input_parameter": "location"} + ], + "response": [{"print": ['Mollusc is a "%s"', "$resp.taxonomy"]}]} + + sample_str = samplegen.generate_sample( + sample, + schema, + env.get_template('examples/sample.py.j2') + ) + + assert sample_str == golden_snippet("sample_basic_async.py") + + def test_generate_sample_basic_unflattenable(): # Note: the sample integration tests are needfully large # and difficult to eyeball parse. They are intended to be integration tests diff --git a/tests/unit/samplegen/test_samplegen.py b/tests/unit/samplegen/test_samplegen.py index 32ef4411f1..5274bc4844 100644 --- a/tests/unit/samplegen/test_samplegen.py +++ b/tests/unit/samplegen/test_samplegen.py @@ -1912,14 +1912,26 @@ def test_generate_sample_spec_basic(): ) opts = Options.build("transport=grpc") specs = list(samplegen.generate_sample_specs(api_schema, opts=opts)) - assert len(specs) == 1 + specs.sort(key=lambda x: x["transport"]) + assert len(specs) == 2 assert specs[0] == { "sample_type": "standalone", "rpc": "Ramshorn", + "transport": "grpc", "request": [], "service": "animalia.mollusca.v1.Squid", - "region_tag": "example_generated_mollusca_v1_Squid_Ramshorn_grpc", + "region_tag": "example_generated_mollusca_v1_Squid_Ramshorn_sync", + "description": "Snippet for ramshorn" + } + + assert specs[1] == { + "sample_type": "standalone", + "rpc": "Ramshorn", + "transport": "grpc-async", + "request": [], + "service": "animalia.mollusca.v1.Squid", + "region_tag": "example_generated_mollusca_v1_Squid_Ramshorn_async", "description": "Snippet for ramshorn" } diff --git a/tests/unit/samplegen/test_template.py b/tests/unit/samplegen/test_template.py index 0eabe9e4f0..ace0129060 100644 --- a/tests/unit/samplegen/test_template.py +++ b/tests/unit/samplegen/test_template.py @@ -700,7 +700,7 @@ def test_print_input_params(): CALLING_FORM_TEMPLATE_TEST_STR = ''' {% import "feature_fragments.j2" as frags %} {{ frags.render_calling_form("TEST_INVOCATION_TXT", calling_form, - calling_form_enum, + calling_form_enum, transport, [{"print": ["Test print statement"]}]) }} ''' @@ -715,7 +715,8 @@ def test_render_calling_form_request(): print("Test print statement") ''', calling_form_enum=CallingForm, - calling_form=CallingForm.Request) + calling_form=CallingForm.Request, + transport="grpc") def test_render_calling_form_paged_all(): @@ -727,7 +728,22 @@ def test_render_calling_form_paged_all(): print("Test print statement") ''', calling_form_enum=CallingForm, - calling_form=CallingForm.RequestPagedAll) + calling_form=CallingForm.RequestPagedAll, + transport="grpc") + + +def test_render_calling_form_paged_all_async(): + check_template(CALLING_FORM_TEMPLATE_TEST_STR, + ''' + # Make the request + page_result = TEST_INVOCATION_TXT + async for response in page_result: + print("Test print statement") + ''', + calling_form_enum=CallingForm, + calling_form=CallingForm.RequestPagedAll, + transport="grpc-async") + def test_render_calling_form_paged(): @@ -740,7 +756,22 @@ def test_render_calling_form_paged(): print("Test print statement") ''', calling_form_enum=CallingForm, - calling_form=CallingForm.RequestPaged) + calling_form=CallingForm.RequestPaged, + transport="grpc") + + +def test_render_calling_form_paged(): + check_template(CALLING_FORM_TEMPLATE_TEST_STR, + ''' + # Make the request + page_result = TEST_INVOCATION_TXT + async for page in page_result.pages(): + for response in page: + print("Test print statement") + ''', + calling_form_enum=CallingForm, + calling_form=CallingForm.RequestPaged, + transport="grpc-async") def test_render_calling_form_streaming_server(): @@ -752,7 +783,20 @@ def test_render_calling_form_streaming_server(): print("Test print statement") ''', calling_form_enum=CallingForm, - calling_form=CallingForm.RequestStreamingServer) + calling_form=CallingForm.RequestStreamingServer, + transport="grpc") + +def test_render_calling_form_streaming_server_async(): + check_template(CALLING_FORM_TEMPLATE_TEST_STR, + ''' + # Make the request + stream = TEST_INVOCATION_TXT + async for response in stream: + print("Test print statement") + ''', + calling_form_enum=CallingForm, + calling_form=CallingForm.RequestStreamingServer, + transport="grpc-async") def test_render_calling_form_streaming_bidi(): @@ -764,7 +808,21 @@ def test_render_calling_form_streaming_bidi(): print("Test print statement") ''', calling_form_enum=CallingForm, - calling_form=CallingForm.RequestStreamingBidi) + calling_form=CallingForm.RequestStreamingBidi, + transport="grpc") + + +def test_render_calling_form_streaming_bidi_async(): + check_template(CALLING_FORM_TEMPLATE_TEST_STR, + ''' + # Make the request + stream = TEST_INVOCATION_TXT + async for response in stream: + print("Test print statement") + ''', + calling_form_enum=CallingForm, + calling_form=CallingForm.RequestStreamingBidi, + transport="grpc-async") def test_render_calling_form_longrunning(): @@ -779,7 +837,23 @@ def test_render_calling_form_longrunning(): print("Test print statement") ''', calling_form_enum=CallingForm, - calling_form=CallingForm.LongRunningRequestPromise) + calling_form=CallingForm.LongRunningRequestPromise, + transport="grpc") + +def test_render_calling_form_longrunning_async(): + check_template(CALLING_FORM_TEMPLATE_TEST_STR, + ''' + # Make the request + operation = TEST_INVOCATION_TXT + + print("Waiting for operation to complete...") + + response = await operation.result() + print("Test print statement") + ''', + calling_form_enum=CallingForm, + calling_form=CallingForm.LongRunningRequestPromise, + transport="grpc-async") def test_render_method_call_basic(): @@ -787,7 +861,7 @@ def test_render_method_call_basic(): ''' {% import "feature_fragments.j2" as frags %} {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, - calling_form, calling_form_enum) }} + calling_form, calling_form_enum, transport) }} ''', ''' client.categorize_mollusc(request=request) @@ -806,16 +880,44 @@ def test_render_method_call_basic(): ], ), calling_form_enum=CallingForm, - calling_form=CallingForm.Request + calling_form=CallingForm.Request, + transport="grpc" ) +def test_render_method_call_basic_async(): + check_template( + ''' + {% import "feature_fragments.j2" as frags %} + {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, + calling_form, calling_form_enum, transport) }} + ''', + ''' + await client.categorize_mollusc(request=request) + ''', + request=samplegen.FullRequest( + request_list=[ + samplegen.TransformedRequest(base="video", + body=True, + single=None), + samplegen.TransformedRequest(base="audio", + body=True, + single=None), + samplegen.TransformedRequest(base="guess", + body=True, + single=None) + ], + ), + calling_form_enum=CallingForm, + calling_form=CallingForm.Request, + transport="grpc-async" + ) def test_render_method_call_basic_flattenable(): check_template( ''' {% import "feature_fragments.j2" as frags %} {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, - calling_form, calling_form_enum) }} + calling_form, calling_form_enum, transport) }} ''', ''' client.categorize_mollusc(video=video, audio=audio, guess=guess) @@ -835,7 +937,8 @@ def test_render_method_call_basic_flattenable(): flattenable=True, ), calling_form_enum=CallingForm, - calling_form=CallingForm.Request + calling_form=CallingForm.Request, + transport="grpc" ) @@ -844,7 +947,7 @@ def test_render_method_call_bidi(): ''' {% import "feature_fragments.j2" as frags %} {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, - calling_form, calling_form_enum) }} + calling_form, calling_form_enum, transport) }} ''', ''' client.categorize_mollusc([video]) @@ -859,7 +962,32 @@ def test_render_method_call_bidi(): ] ), calling_form_enum=CallingForm, - calling_form=CallingForm.RequestStreamingBidi + calling_form=CallingForm.RequestStreamingBidi, + transport="grpc", + ) + +def test_render_method_call_bidi_async(): + check_template( + ''' + {% import "feature_fragments.j2" as frags %} + {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, + calling_form, calling_form_enum, transport) }} + ''', + ''' + await client.categorize_mollusc([video]) + ''', + request=samplegen.FullRequest( + request_list=[ + samplegen.TransformedRequest( + base="video", + body=True, + single=None + ) + ] + ), + calling_form_enum=CallingForm, + calling_form=CallingForm.RequestStreamingBidi, + transport="grpc-async", ) @@ -868,7 +996,7 @@ def test_render_method_call_client(): ''' {% import "feature_fragments.j2" as frags %} {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, - calling_form, calling_form_enum) }} + calling_form, calling_form_enum, transport) }} ''', ''' client.categorize_mollusc([video]) @@ -883,7 +1011,32 @@ def test_render_method_call_client(): ] ), calling_form_enum=CallingForm, - calling_form=CallingForm.RequestStreamingClient + calling_form=CallingForm.RequestStreamingClient, + transport="grpc", + ) + +def test_render_method_call_client_async(): + check_template( + ''' + {% import "feature_fragments.j2" as frags %} + {{ frags.render_method_call({"rpc": "CategorizeMollusc", "request": request}, + calling_form, calling_form_enum, transport) }} + ''', + ''' + await client.categorize_mollusc([video]) + ''', + request=samplegen.FullRequest( + request_list=[ + samplegen.TransformedRequest( + base="video", + body=True, + single=None + ) + ] + ), + calling_form_enum=CallingForm, + calling_form=CallingForm.RequestStreamingClient, + transport="grpc-async", )