From b784a4307d72c74afa1e18610ec5b9c3655a965a Mon Sep 17 00:00:00 2001 From: Michael Mercier Date: Thu, 6 Jan 2022 19:15:40 +0100 Subject: [PATCH] Add python async example for hellostreamingworld using generator (#27343) * Add python async example for hellostreamingworld using generator * add stub.read() client example + fix Copyrights + small improvements * Format and lint + remove exernal generator * Apply lint and auto-format --- .../async_greeter_client.py | 47 ++++++ .../async_greeter_server.py | 49 ++++++ .../hellostreamingworld_pb2.py | 143 ++++++++++++++++++ .../hellostreamingworld_pb2_grpc.py | 70 +++++++++ 4 files changed, 309 insertions(+) create mode 100644 examples/python/hellostreamingworld/async_greeter_client.py create mode 100644 examples/python/hellostreamingworld/async_greeter_server.py create mode 100644 examples/python/hellostreamingworld/hellostreamingworld_pb2.py create mode 100644 examples/python/hellostreamingworld/hellostreamingworld_pb2_grpc.py diff --git a/examples/python/hellostreamingworld/async_greeter_client.py b/examples/python/hellostreamingworld/async_greeter_client.py new file mode 100644 index 00000000000..754e5e3f4a4 --- /dev/null +++ b/examples/python/hellostreamingworld/async_greeter_client.py @@ -0,0 +1,47 @@ +# Copyright 2021 gRPC authors. +# +# 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. +"""The Python AsyncIO implementation of the GRPC hellostreamingworld.MultiGreeter client.""" + +import asyncio +import logging + +import grpc +import hellostreamingworld_pb2 +import hellostreamingworld_pb2_grpc + + +async def run() -> None: + async with grpc.aio.insecure_channel("localhost:50051") as channel: + stub = hellostreamingworld_pb2_grpc.MultiGreeterStub(channel) + + # Read from an async generator + async for response in stub.sayHello( + hellostreamingworld_pb2.HelloRequest(name="you")): + print("Greeter client received from async generator: " + + response.message) + + # Direct read from the stub + hello_stream = stub.sayHello( + hellostreamingworld_pb2.HelloRequest(name="you")) + while True: + response = await hello_stream.read() + if response == grpc.aio.EOF: + break + print("Greeter client received from direct read: " + + response.message) + + +if __name__ == "__main__": + logging.basicConfig() + asyncio.run(run()) diff --git a/examples/python/hellostreamingworld/async_greeter_server.py b/examples/python/hellostreamingworld/async_greeter_server.py new file mode 100644 index 00000000000..d87621c1db0 --- /dev/null +++ b/examples/python/hellostreamingworld/async_greeter_server.py @@ -0,0 +1,49 @@ +# Copyright 2021 gRPC authors. +# +# 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. +"""The Python AsyncIO implementation of the GRPC hellostreamingworld.MultiGreeter server.""" + +import asyncio +import logging + +import grpc +from hellostreamingworld_pb2 import HelloReply +from hellostreamingworld_pb2 import HelloRequest +from hellostreamingworld_pb2_grpc import MultiGreeterServicer +from hellostreamingworld_pb2_grpc import add_MultiGreeterServicer_to_server + +NUMBER_OF_REPLY = 10 + + +class Greeter(MultiGreeterServicer): + + async def sayHello(self, request: HelloRequest, + context: grpc.aio.ServicerContext) -> HelloReply: + logging.info("Serving sayHello request %s", request) + for i in range(NUMBER_OF_REPLY): + yield HelloReply(message=f"Hello number {i}, {request.name}!") + + +async def serve() -> None: + server = grpc.aio.server() + add_MultiGreeterServicer_to_server(Greeter(), server) + listen_addr = "[::]:50051" + server.add_insecure_port(listen_addr) + logging.info("Starting server on %s", listen_addr) + await server.start() + await server.wait_for_termination() + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + asyncio.run(serve()) diff --git a/examples/python/hellostreamingworld/hellostreamingworld_pb2.py b/examples/python/hellostreamingworld/hellostreamingworld_pb2.py new file mode 100644 index 00000000000..5a7d7394a24 --- /dev/null +++ b/examples/python/hellostreamingworld/hellostreamingworld_pb2.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: hellostreamingworld.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='hellostreamingworld.proto', + package='hellostreamingworld', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x19hellostreamingworld.proto\x12\x13hellostreamingworld\"3\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rnum_greetings\x18\x02 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2b\n\x0cMultiGreeter\x12R\n\x08sayHello\x12!.hellostreamingworld.HelloRequest\x1a\x1f.hellostreamingworld.HelloReply\"\x00\x30\x01\x62\x06proto3' +) + + + + +_HELLOREQUEST = _descriptor.Descriptor( + name='HelloRequest', + full_name='hellostreamingworld.HelloRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='hellostreamingworld.HelloRequest.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='num_greetings', full_name='hellostreamingworld.HelloRequest.num_greetings', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=50, + serialized_end=101, +) + + +_HELLOREPLY = _descriptor.Descriptor( + name='HelloReply', + full_name='hellostreamingworld.HelloReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='hellostreamingworld.HelloReply.message', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=103, + serialized_end=132, +) + +DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST +DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), { + 'DESCRIPTOR' : _HELLOREQUEST, + '__module__' : 'hellostreamingworld_pb2' + # @@protoc_insertion_point(class_scope:hellostreamingworld.HelloRequest) + }) +_sym_db.RegisterMessage(HelloRequest) + +HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), { + 'DESCRIPTOR' : _HELLOREPLY, + '__module__' : 'hellostreamingworld_pb2' + # @@protoc_insertion_point(class_scope:hellostreamingworld.HelloReply) + }) +_sym_db.RegisterMessage(HelloReply) + + + +_MULTIGREETER = _descriptor.ServiceDescriptor( + name='MultiGreeter', + full_name='hellostreamingworld.MultiGreeter', + file=DESCRIPTOR, + index=0, + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_start=134, + serialized_end=232, + methods=[ + _descriptor.MethodDescriptor( + name='sayHello', + full_name='hellostreamingworld.MultiGreeter.sayHello', + index=0, + containing_service=None, + input_type=_HELLOREQUEST, + output_type=_HELLOREPLY, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), +]) +_sym_db.RegisterServiceDescriptor(_MULTIGREETER) + +DESCRIPTOR.services_by_name['MultiGreeter'] = _MULTIGREETER + +# @@protoc_insertion_point(module_scope) diff --git a/examples/python/hellostreamingworld/hellostreamingworld_pb2_grpc.py b/examples/python/hellostreamingworld/hellostreamingworld_pb2_grpc.py new file mode 100644 index 00000000000..b0ba42dfc22 --- /dev/null +++ b/examples/python/hellostreamingworld/hellostreamingworld_pb2_grpc.py @@ -0,0 +1,70 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import hellostreamingworld_pb2 as hellostreamingworld__pb2 + + +class MultiGreeterStub(object): + """The greeting service definition. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.sayHello = channel.unary_stream( + '/hellostreamingworld.MultiGreeter/sayHello', + request_serializer=hellostreamingworld__pb2.HelloRequest.SerializeToString, + response_deserializer=hellostreamingworld__pb2.HelloReply.FromString, + ) + + +class MultiGreeterServicer(object): + """The greeting service definition. + """ + + def sayHello(self, request, context): + """Sends multiple greetings + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_MultiGreeterServicer_to_server(servicer, server): + rpc_method_handlers = { + 'sayHello': grpc.unary_stream_rpc_method_handler( + servicer.sayHello, + request_deserializer=hellostreamingworld__pb2.HelloRequest.FromString, + response_serializer=hellostreamingworld__pb2.HelloReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hellostreamingworld.MultiGreeter', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class MultiGreeter(object): + """The greeting service definition. + """ + + @staticmethod + def sayHello(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/hellostreamingworld.MultiGreeter/sayHello', + hellostreamingworld__pb2.HelloRequest.SerializeToString, + hellostreamingworld__pb2.HelloReply.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)