diff --git a/python/helloworld/.gitignore b/python/helloworld/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0d20b6487c61e7d1bde93acf4a14b7a89083a16d --- /dev/null +++ b/python/helloworld/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/python/helloworld/README.md b/python/helloworld/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2bbfc4b01781a843004ead70bb3beb18c54c0dfd --- /dev/null +++ b/python/helloworld/README.md @@ -0,0 +1,111 @@ +# gRPC Python Hello World Tutorial + +### Install gRPC +Make sure you have built gRPC Python from source on your system. Follow the instructions here: +[https://github.com/grpc/grpc/blob/master/src/python/README.md](https://github.com/grpc/grpc/blob/master/src/python/README.md). + +This gives you a python virtual environment with installed gRPC Python +in GRPC_ROOT/python2.7_virtual_environment. GRPC_ROOT is the path to which you +have cloned the [gRPC git repo](https://github.com/grpc/grpc). + +### Get the tutorial source code + +The example code for this and our other examples live in the `grpc-common` +GitHub repository. Clone this repository to your local machine by running the +following command: + + +```sh +$ git clone https://github.com/google/grpc-common.git +``` + +Change your current directory to grpc-common/python/helloworld + +```sh +$ cd grpc-common/python/helloworld/ +``` + +### Defining a service + +The first step in creating our example is to define a *service*: an RPC +service specifies the methods that can be called remotely with their parameters +and return types. As you saw in the +[overview](#protocolbuffers) above, gRPC does this using [protocol +buffers](https://developers.google.com/protocol-buffers/docs/overview). We +use the protocol buffers interface definition language (IDL) to define our +service methods, and define the parameters and return +types as protocol buffer message types. Both the client and the +server use interface code generated from the service definition. + +Here's our example service definition, defined using protocol buffers IDL in +[helloworld.proto](https://github.com/grpc/grpc-common/blob/master/python/helloworld/helloworld.proto). The `Greeting` +service has one method, `hello`, that lets the server receive a single +`HelloRequest` +message from the remote client containing the user's name, then send back +a greeting in a single `HelloReply`. This is the simplest type of RPC you +can specify in gRPC. + +``` +syntax = "proto2"; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + optional string name = 1; +} + +// The response message containing the greetings +message HelloReply { + optional string message = 1; +} + +``` + +<a name="generating"></a> +### Generating gRPC code + +Once we've defined our service, we use the protocol buffer compiler +`protoc` to generate the special client and server code we need to create +our application. The generated code contains both stub code for clients to +use and an abstract interface for servers to implement, both with the method +defined in our `Greeting` service. + +To generate the client and server side interfaces: + +```sh +$ ./run_codegen.sh +``` +Which internally invokes the proto-compiler as: + +```sh +$ protoc -I . --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` helloworld.proto +``` + +Optionally, you can just skip the code generation step as the generated python module has already +been generated for you (helloworld_pb2.py). + +### The client + +Client-side code can be found in [greeter_client.py](https://github.com/grpc/grpc-common/blob/master/python/helloworld/greeter_client.py). + +You can run the client using: + +```sh +$ ./run_client.sh +``` + + +### The server + +Server side code can be found in [greeter_server.py](https://github.com/grpc/grpc-common/blob/master/python/helloworld/greeter_server.py). + +You can run the server using: + +```sh +$ ./run_server.sh +``` diff --git a/python/helloworld/greeter_client.py b/python/helloworld/greeter_client.py new file mode 100755 index 0000000000000000000000000000000000000000..370ce46770302ea7aa222e28a20d512768db0b8f --- /dev/null +++ b/python/helloworld/greeter_client.py @@ -0,0 +1,44 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the GRPC helloworld.Greeter client.""" + +import helloworld_pb2 + +_TIMEOUT_SECONDS = 10 + + +def run(): + with helloworld_pb2.early_adopter_create_Greeter_stub('localhost', 50051) as stub: + response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS) + print "Greeter client received: " + response.message + + +if __name__ == '__main__': + run() diff --git a/python/helloworld/greeter_server.py b/python/helloworld/greeter_server.py new file mode 100644 index 0000000000000000000000000000000000000000..81353666b10ffe022d86eb755b147dbb2064cdb8 --- /dev/null +++ b/python/helloworld/greeter_server.py @@ -0,0 +1,56 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the GRPC helloworld.Greeter server.""" + +import time + +import helloworld_pb2 + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class Greeter(helloworld_pb2.EarlyAdopterGreeterServicer): + + def SayHello(self, request, context): + return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) + + +def serve(): + server = helloworld_pb2.early_adopter_create_Greeter_server( + Greeter(), 50051, None, None) + server.start() + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop() + +if __name__ == '__main__': + serve() diff --git a/python/helloworld/helloworld.proto b/python/helloworld/helloworld.proto new file mode 100644 index 0000000000000000000000000000000000000000..1ade8fb2acb2e3386d7da5031bccd188d5346a16 --- /dev/null +++ b/python/helloworld/helloworld.proto @@ -0,0 +1,49 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; + +//TODO: see https://github.com/grpc/grpc/issues/814 +//package examples; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + optional string name = 1; +} + +// The response message containing the greetings +message HelloReply { + optional string message = 1; +} diff --git a/python/helloworld/helloworld_pb2.py b/python/helloworld/helloworld_pb2.py new file mode 100644 index 0000000000000000000000000000000000000000..d35ebb77c664c21507f0cca1ded0b16322c71f42 --- /dev/null +++ b/python/helloworld/helloworld_pb2.py @@ -0,0 +1,158 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: helloworld.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +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 +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='helloworld.proto', + package='', + serialized_pb=_b('\n\x10helloworld.proto\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t23\n\x07Greeter\x12(\n\x08SayHello\x12\r.HelloRequest\x1a\x0b.HelloReply\"\x00') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_HELLOREQUEST = _descriptor.Descriptor( + name='HelloRequest', + full_name='HelloRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='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, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=20, + serialized_end=48, +) + + +_HELLOREPLY = _descriptor.Descriptor( + name='HelloReply', + full_name='HelloReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='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, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=50, + serialized_end=79, +) + +DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST +DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY + +HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict( + DESCRIPTOR = _HELLOREQUEST, + __module__ = 'helloworld_pb2' + # @@protoc_insertion_point(class_scope:HelloRequest) + )) +_sym_db.RegisterMessage(HelloRequest) + +HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict( + DESCRIPTOR = _HELLOREPLY, + __module__ = 'helloworld_pb2' + # @@protoc_insertion_point(class_scope:HelloReply) + )) +_sym_db.RegisterMessage(HelloReply) + + +import abc +from grpc._adapter import fore +from grpc._adapter import rear +from grpc.framework.assembly import implementations +from grpc.framework.assembly import utilities +class EarlyAdopterGreeterServicer(object): + """<fill me in later!>""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def SayHello(self, request): + raise NotImplementedError() +class EarlyAdopterGreeterServer(object): + """<fill me in later!>""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def start(self): + raise NotImplementedError() + @abc.abstractmethod + def stop(self): + raise NotImplementedError() +class EarlyAdopterGreeterStub(object): + """<fill me in later!>""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def SayHello(self, request): + raise NotImplementedError() + SayHello.async = None +def early_adopter_create_Greeter_server(servicer, port, root_certificates, key_chain_pairs): + method_implementations = { + "SayHello": utilities.unary_unary_inline(servicer.SayHello), + } + import helloworld_pb2 + request_deserializers = { + "SayHello": helloworld_pb2.HelloRequest.FromString, + } + response_serializers = { + "SayHello": lambda x: x.SerializeToString(), + } + link = fore.activated_fore_link(port, request_deserializers, response_serializers, root_certificates, key_chain_pairs) + return implementations.assemble_service(method_implementations, link) +def early_adopter_create_Greeter_stub(host, port): + method_implementations = { + "SayHello": utilities.unary_unary_inline(None), + } + import helloworld_pb2 + response_deserializers = { + "SayHello": helloworld_pb2.HelloReply.FromString, + } + request_serializers = { + "SayHello": lambda x: x.SerializeToString(), + } + link = rear.activated_rear_link(host, port, request_serializers, response_deserializers) + return implementations.assemble_dynamic_inline_stub(method_implementations, link) +# @@protoc_insertion_point(module_scope) diff --git a/python/helloworld/run_client.sh b/python/helloworld/run_client.sh new file mode 100755 index 0000000000000000000000000000000000000000..095e6bc2f0e46a9694adbf7ed9de6fde2c4e877f --- /dev/null +++ b/python/helloworld/run_client.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This is where you have cloned out the https://github.com/grpc/grpc repository +# And built gRPC Python. +# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS +GRPC_ROOT=~/github/grpc + +$GRPC_ROOT/python2.7_virtual_environment/bin/python greeter_client.py diff --git a/python/helloworld/run_codegen.sh b/python/helloworld/run_codegen.sh new file mode 100755 index 0000000000000000000000000000000000000000..ed40386bc0cff0f77b99ec548117bb86b353eba1 --- /dev/null +++ b/python/helloworld/run_codegen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs. +protoc -I . --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` helloworld.proto diff --git a/python/helloworld/run_server.sh b/python/helloworld/run_server.sh new file mode 100755 index 0000000000000000000000000000000000000000..13b009e6cc75caa49dcaa70c4f9dcc0031433322 --- /dev/null +++ b/python/helloworld/run_server.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# This is where you have cloned out the https://github.com/grpc/grpc repository +# And built gRPC Python. +# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS +GRPC_ROOT=~/github/grpc + +$GRPC_ROOT/python2.7_virtual_environment/bin/python greeter_server.py +