grpc.io/public/docs/tutorials/basic/python/index.html

497 lines
34 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/css/style.css">
<title>
gRPC Basics - Python &ndash; gRPC
</title>
<link rel="apple-touch-icon" href="/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" type="image/png" href="/favicons/android-chrome-192x192.png" sizes="192x192" >
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/favicons/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/favicons/manifest.json">
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#2DA6B0">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/favicons/mstile-150x150.png">
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-60127042-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-60127042-1');
</script>
</head>
<body>
<div id="landing-content">
<div class="row">
<div class="topbannersub">
<nav class="navbar navbar-expand-md navbar-dark topnav">
<a class="navbar-brand" href="https://cjyabraham.github.io/">
<img src="https://cjyabraham.github.io/img/grpc-logo.png" width="114" height="50">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="topnav, collapse navbar-collapse" id="navbarSupportedContent" style="float:right !important">
<ul class="navbar-nav ml-auto">
<li class="nav-item ">
<a class="nav-link" href="https://cjyabraham.github.io/about/">About</a>
</li>
<li class="nav-item dropdown active">
<a class="nav-link dropdown-toggle" href="https://cjyabraham.github.io/docs/" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Docs
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/docs">
Overview
</a>
<a class="dropdown-item" href="/docs/quickstart/">
Quick Start
</a>
<a class="dropdown-item" href="/docs/guides/">
Guides
</a>
<a class="dropdown-item" href="/docs/tutorials/">
Tutorials
</a>
<a class="dropdown-item" href="/docs/reference/">
Reference
</a>
<a class="dropdown-item" href="/docs/samples/">
Samples
</a>
<a class="dropdown-item" href="/docs/talks">
Presentations
</a>
</div>
</li>
<li class="nav-item ">
<a class="nav-link" href="/blog">
Blog
</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="/community">Community</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://packages.grpc.io/">
Packages
</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="https://cjyabraham.github.io/faq/">FAQ</a>
</li>
</ul>
</div>
</nav>
<div class="headertext">Documentation</div>
</div>
</div>
</div>
<div class="subnav d-none d-md-block">
<a href="https://cjyabraham.github.io/docs/" >Overview</a>
| <a href="https://cjyabraham.github.io/docs/quickstart/" >Quick Start</a>
| <a href="https://cjyabraham.github.io/docs/guides/" >Guides</a>
| <a href="https://cjyabraham.github.io/docs/tutorials/" class="active">Tutorials</a>
| <a href="https://cjyabraham.github.io/docs/reference/" >Reference</a>
| <a href="https://cjyabraham.github.io/docs/samples/" >Samples</a>
| <a href="https://cjyabraham.github.io/docs/talks/" >Presentations</a>
</div>
<div class="quickstartcols">
<div class="quickstartcol1">
<h8>Tutorials</h8>
<a href="https://cjyabraham.github.io/docs/tutorials/async/helloasync-cpp/" >Async - C++</a>
<a href="https://cjyabraham.github.io/docs/tutorials/auth/oauth2-objective-c/" >Auth - Objective C</a>
<h8>Basic</h8>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/c/" >C++</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/csharp/" >C#</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/dart/" >Dart</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/go/" >Go</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/java/" >Java</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/android/" >Android Java</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/node/" >Node</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/objective-c/" >Objective-C</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/php/" >PHP</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/python/" class="active">Python</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/ruby/" >Ruby</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/web/" >Web</a>
</div>
<div class="quickstartcol2" style="margin-top:4%">
<h3 style="margin-top:0px;">gRPC Basics - Python</h3>
<p>This tutorial provides a basic Python programmer&rsquo;s introduction
to working with gRPC.</p>
<p>By walking through this example you&rsquo;ll learn how to:</p>
<ul>
<li>Define a service in a .proto file.</li>
<li>Generate server and client code using the protocol buffer compiler.</li>
<li>Use the Python gRPC API to write a simple client and server for your service.</li>
</ul>
<p>It assumes that you have read the <a href="/docs/guides/#overview">Overview</a> and are familiar
with <a href="https://developers.google.com/protocol-buffers/docs/overview">protocol
buffers</a>. You can
find out more in the <a href="https://developers.google.com/protocol-buffers/docs/proto3">proto3 language
guide</a> and <a href="https://developers.google.com/protocol-buffers/docs/reference/python-generated">Python
generated code
guide</a>.</p>
<div id="toc"></div>
<h3 id="why-use-grpc">Why use gRPC?</h3>
<p>This example is a simple route mapping application that lets clients get
information about features on their route, create a summary of their route, and
exchange route information such as traffic updates with the server and other
clients.</p>
<p>With gRPC you can define your service once in a .proto file and implement
clients and servers in any of gRPC&rsquo;s supported languages, which in turn can be
run in environments ranging from servers inside Google to your own tablet -
all the complexity of communication between different languages and environments
is handled for you by gRPC. You also get all the advantages of working with
protocol buffers, including efficient serialization, a simple IDL, and easy
interface updating.</p>
<h3 id="example-code-and-setup">Example code and setup</h3>
<p>The example code for this tutorial is in
<a href="https://github.com/grpc/grpc/tree/v1.20.0/examples/python/route_guide">grpc/grpc/examples/python/route_guide</a>.
To download the example, clone the <code>grpc</code> repository by running the following
command:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ git clone -b v1.20.0 https://github.com/grpc/grpc</code></pre></div>
<p>Then change your current directory to <code>examples/python/route_guide</code> in the repository:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ cd grpc/examples/python/route_guide</code></pre></div>
<p>You also should have the relevant tools installed to generate the server and
client interface code - if you don&rsquo;t already, follow the setup instructions in
<a href="/docs/quickstart/python">the Python quick start guide</a>.</p>
<h3 id="defining-the-service">Defining the service</h3>
<p>Your first step (as you&rsquo;ll know from the <a href="/docs/guides/#overview">Overview</a>) is to
define the gRPC <em>service</em> and the method <em>request</em> and <em>response</em> types using
<a href="https://developers.google.com/protocol-buffers/docs/overview">protocol
buffers</a>. You can
see the complete .proto file in
<a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/protos/route_guide.proto"><code>examples/protos/route_guide.proto</code></a>.</p>
<p>To define a service, you specify a named <code>service</code> in your .proto file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#66d9ef">service</span> RouteGuide {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#75715e">// (Method definitions not shown)
</span><span style="color:#75715e"></span>}</code></pre></div>
<p>Then you define <code>rpc</code> methods inside your service definition, specifying their
request and response types. gRPC lets you define four kinds of service method,
all of which are used in the <code>RouteGuide</code> service:</p>
<ul>
<li>A <em>simple RPC</em> where the client sends a request to the server using the stub
and waits for a response to come back, just like a normal function call.</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Obtains the feature at a given position.
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> GetFeature(Point) <span style="color:#66d9ef">returns</span> (Feature) {}</code></pre></div>
<ul>
<li>A <em>response-streaming RPC</em> where the client sends a request to the server and
gets a stream to read a sequence of messages back. The client reads from the
returned stream until there are no more messages. As you can see in the
example, you specify a response-streaming method by placing the <code>stream</code>
keyword before the <em>response</em> type.</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Obtains the Features available within the given Rectangle. Results are
</span><span style="color:#75715e">// streamed rather than returned at once (e.g. in a response message with a
</span><span style="color:#75715e">// repeated field), as the rectangle may cover a large area and contain a
</span><span style="color:#75715e">// huge number of features.
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> ListFeatures(Rectangle) <span style="color:#66d9ef">returns</span> (stream Feature) {}</code></pre></div>
<ul>
<li>A <em>request-streaming RPC</em> where the client writes a sequence of messages and
sends them to the server, again using a provided stream. Once the client has
finished writing the messages, it waits for the server to read them all and
return its response. You specify a request-streaming method by placing the
<code>stream</code> keyword before the <em>request</em> type.</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Accepts a stream of Points on a route being traversed, returning a
</span><span style="color:#75715e">// RouteSummary when traversal is completed.
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> RecordRoute(stream Point) <span style="color:#66d9ef">returns</span> (RouteSummary) {}</code></pre></div>
<ul>
<li>A <em>bidirectionally-streaming RPC</em> where both sides send a sequence of messages
using a read-write stream. The two streams operate independently, so clients
and servers can read and write in whatever order they like: for example, the
server could wait to receive all the client messages before writing its
responses, or it could alternately read a message then write a message, or
some other combination of reads and writes. The order of messages in each
stream is preserved. You specify this type of method by placing the <code>stream</code>
keyword before both the request and the response.</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Accepts a stream of RouteNotes sent while a route is being traversed,
</span><span style="color:#75715e">// while receiving other RouteNotes (e.g. from other users).
</span><span style="color:#75715e"></span><span style="color:#66d9ef">rpc</span> RouteChat(stream RouteNote) <span style="color:#66d9ef">returns</span> (stream RouteNote) {}</code></pre></div>
<p>Your .proto file also contains protocol buffer message type definitions for all
the request and response types used in our service methods - for example, here&rsquo;s
the <code>Point</code> message type:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#75715e">// Points are represented as latitude-longitude pairs in the E7 representation
</span><span style="color:#75715e">// (degrees multiplied by 10**7 and rounded to the nearest integer).
</span><span style="color:#75715e">// Latitudes should be in the range +/- 90 degrees and longitude should be in
</span><span style="color:#75715e">// the range +/- 180 degrees (inclusive).
</span><span style="color:#75715e"></span><span style="color:#66d9ef">message</span> <span style="color:#a6e22e">Point</span> {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">int32</span> latitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">int32</span> longitude <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span>;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span>}</code></pre></div>
<h3 id="generating-client-and-server-code">Generating client and server code</h3>
<p>Next you need to generate the gRPC client and server interfaces from your .proto
service definition.</p>
<p>First, install the grpcio-tools package:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ pip install grpcio-tools</code></pre></div>
<p>Use the following command to generate the Python code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ python -m grpc_tools.protoc -I../../protos --python_out<span style="color:#f92672">=</span>. --grpc_python_out<span style="color:#f92672">=</span>. ../../protos/route_guide.proto</code></pre></div>
<p>Note that as we&rsquo;ve already provided a version of the generated code in the
example directory, running this command regenerates the appropriate file rather
than creates a new one. The generated code files are called
<code>route_guide_pb2.py</code> and <code>route_guide_pb2_grpc.py</code> and contain:</p>
<ul>
<li>classes for the messages defined in route_guide.proto</li>
<li>classes for the service defined in route_guide.proto
<ul>
<li><code>RouteGuideStub</code>, which can be used by clients to invoke RouteGuide RPCs</li>
<li><code>RouteGuideServicer</code>, which defines the interface for implementations
of the RouteGuide service</li>
</ul></li>
<li>a function for the service defined in route_guide.proto
<ul>
<li><code>add_RouteGuideServicer_to_server</code>, which adds a RouteGuideServicer to
a <code>grpc.Server</code></li>
</ul></li>
</ul>
<p>Note: The <code>2</code> in pb2 indicates that the generated code is following Protocol Buffers Python API version 2. Version 1 is obsolete. It has no relation to the Protocol Buffers Language version, which is the one indicated by <code>syntax = &quot;proto3&quot;</code> or <code>syntax = &quot;proto2&quot;</code> in a .proto file.</p>
<p><a name="server"></a></p>
<h3 id="creating-the-server">Creating the server</h3>
<p>First let&rsquo;s look at how you create a <code>RouteGuide</code> server. If you&rsquo;re only
interested in creating gRPC clients, you can skip this section and go straight
to <a href="#client">Creating the client</a> (though you might find it interesting
anyway!).</p>
<p>Creating and running a <code>RouteGuide</code> server breaks down into two work items:
- Implementing the servicer interface generated from our service definition with
functions that perform the actual &ldquo;work&rdquo; of the service.
- Running a gRPC server to listen for requests from clients and transmit
responses.</p>
<p>You can find the example <code>RouteGuide</code> server in
<a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/python/route_guide/route_guide_server.py">examples/python/route_guide/route_guide_server.py</a>.</p>
<h4 id="implementing-routeguide">Implementing RouteGuide</h4>
<p><code>route_guide_server.py</code> has a <code>RouteGuideServicer</code> class that subclasses the
generated class <code>route_guide_pb2_grpc.RouteGuideServicer</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># RouteGuideServicer provides an implementation of the methods of the RouteGuide service.</span>
<span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RouteGuideServicer</span>(route_guide_pb2_grpc<span style="color:#f92672">.</span>RouteGuideServicer):</code></pre></div>
<p><code>RouteGuideServicer</code> implements all the <code>RouteGuide</code> service methods.</p>
<h5 id="simple-rpc">Simple RPC</h5>
<p>Let&rsquo;s look at the simplest type first, <code>GetFeature</code>, which just gets a <code>Point</code>
from the client and returns the corresponding feature information from its
database in a <code>Feature</code>.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">GetFeature</span>(self, request, context):
feature <span style="color:#f92672">=</span> get_feature(self<span style="color:#f92672">.</span>db, request)
<span style="color:#66d9ef">if</span> feature <span style="color:#f92672">is</span> None:
<span style="color:#66d9ef">return</span> route_guide_pb2<span style="color:#f92672">.</span>Feature(name<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&#34;</span>, location<span style="color:#f92672">=</span>request)
<span style="color:#66d9ef">else</span>:
<span style="color:#66d9ef">return</span> feature</code></pre></div>
<p>The method is passed a <code>route_guide_pb2.Point</code> request for the RPC, and a
<code>grpc.ServicerContext</code> object that provides RPC-specific information such as
timeout limits. It returns a <code>route_guide_pb2.Feature</code> response.</p>
<h5 id="response-streaming-rpc">Response-streaming RPC</h5>
<p>Now let&rsquo;s look at the next method. <code>ListFeatures</code> is a response-streaming RPC
that sends multiple <code>Feature</code>s to the client.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">ListFeatures</span>(self, request, context):
left <span style="color:#f92672">=</span> min(request<span style="color:#f92672">.</span>lo<span style="color:#f92672">.</span>longitude, request<span style="color:#f92672">.</span>hi<span style="color:#f92672">.</span>longitude)
right <span style="color:#f92672">=</span> max(request<span style="color:#f92672">.</span>lo<span style="color:#f92672">.</span>longitude, request<span style="color:#f92672">.</span>hi<span style="color:#f92672">.</span>longitude)
top <span style="color:#f92672">=</span> max(request<span style="color:#f92672">.</span>lo<span style="color:#f92672">.</span>latitude, request<span style="color:#f92672">.</span>hi<span style="color:#f92672">.</span>latitude)
bottom <span style="color:#f92672">=</span> min(request<span style="color:#f92672">.</span>lo<span style="color:#f92672">.</span>latitude, request<span style="color:#f92672">.</span>hi<span style="color:#f92672">.</span>latitude)
<span style="color:#66d9ef">for</span> feature <span style="color:#f92672">in</span> self<span style="color:#f92672">.</span>db:
<span style="color:#66d9ef">if</span> (feature<span style="color:#f92672">.</span>location<span style="color:#f92672">.</span>longitude <span style="color:#f92672">&gt;=</span> left <span style="color:#f92672">and</span>
feature<span style="color:#f92672">.</span>location<span style="color:#f92672">.</span>longitude <span style="color:#f92672">&lt;=</span> right <span style="color:#f92672">and</span>
feature<span style="color:#f92672">.</span>location<span style="color:#f92672">.</span>latitude <span style="color:#f92672">&gt;=</span> bottom <span style="color:#f92672">and</span>
feature<span style="color:#f92672">.</span>location<span style="color:#f92672">.</span>latitude <span style="color:#f92672">&lt;=</span> top):
<span style="color:#66d9ef">yield</span> feature</code></pre></div>
<p>Here the request message is a <code>route_guide_pb2.Rectangle</code> within which the
client wants to find <code>Feature</code>s. Instead of returning a single response the
method yields zero or more responses.</p>
<h5 id="request-streaming-rpc">Request-streaming RPC</h5>
<p>The request-streaming method <code>RecordRoute</code> uses an
<a href="https://docs.python.org/2/library/stdtypes.html#iterator-types">iterator</a> of
request values and returns a single response value.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">RecordRoute</span>(self, request_iterator, context):
point_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
feature_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
distance <span style="color:#f92672">=</span> <span style="color:#ae81ff">0.0</span>
prev_point <span style="color:#f92672">=</span> None
start_time <span style="color:#f92672">=</span> time<span style="color:#f92672">.</span>time()
<span style="color:#66d9ef">for</span> point <span style="color:#f92672">in</span> request_iterator:
point_count <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
<span style="color:#66d9ef">if</span> get_feature(self<span style="color:#f92672">.</span>db, point):
feature_count <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
<span style="color:#66d9ef">if</span> prev_point:
distance <span style="color:#f92672">+=</span> get_distance(prev_point, point)
prev_point <span style="color:#f92672">=</span> point
elapsed_time <span style="color:#f92672">=</span> time<span style="color:#f92672">.</span>time() <span style="color:#f92672">-</span> start_time
<span style="color:#66d9ef">return</span> route_guide_pb2<span style="color:#f92672">.</span>RouteSummary(point_count<span style="color:#f92672">=</span>point_count,
feature_count<span style="color:#f92672">=</span>feature_count,
distance<span style="color:#f92672">=</span>int(distance),
elapsed_time<span style="color:#f92672">=</span>int(elapsed_time))</code></pre></div>
<h5 id="bidirectional-streaming-rpc">Bidirectional streaming RPC</h5>
<p>Lastly let&rsquo;s look at the bidirectionally-streaming method <code>RouteChat</code>.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">RouteChat</span>(self, request_iterator, context):
prev_notes <span style="color:#f92672">=</span> []
<span style="color:#66d9ef">for</span> new_note <span style="color:#f92672">in</span> request_iterator:
<span style="color:#66d9ef">for</span> prev_note <span style="color:#f92672">in</span> prev_notes:
<span style="color:#66d9ef">if</span> prev_note<span style="color:#f92672">.</span>location <span style="color:#f92672">==</span> new_note<span style="color:#f92672">.</span>location:
<span style="color:#66d9ef">yield</span> prev_note
prev_notes<span style="color:#f92672">.</span>append(new_note)</code></pre></div>
<p>This method&rsquo;s semantics are a combination of those of the request-streaming
method and the response-streaming method. It is passed an iterator of request
values and is itself an iterator of response values.</p>
<h4 id="starting-the-server">Starting the server</h4>
<p>Once you have implemented all the <code>RouteGuide</code> methods, the next step is to
start up a gRPC server so that clients can actually use your service:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">serve</span>():
server <span style="color:#f92672">=</span> grpc<span style="color:#f92672">.</span>server(futures<span style="color:#f92672">.</span>ThreadPoolExecutor(max_workers<span style="color:#f92672">=</span><span style="color:#ae81ff">10</span>))
route_guide_pb2_grpc<span style="color:#f92672">.</span>add_RouteGuideServicer_to_server(
RouteGuideServicer(), server)
server<span style="color:#f92672">.</span>add_insecure_port(<span style="color:#e6db74">&#39;[::]:50051&#39;</span>)
server<span style="color:#f92672">.</span>start()</code></pre></div>
<p>Because <code>start()</code> does not block you may need to sleep-loop if there is nothing
else for your code to do while serving.</p>
<p><a name="client"></a></p>
<h3 id="creating-the-client">Creating the client</h3>
<p>You can see the complete example client code in
<a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/python/route_guide/route_guide_client.py">examples/python/route_guide/route_guide_client.py</a>.</p>
<h4 id="creating-a-stub">Creating a stub</h4>
<p>To call service methods, we first need to create a <em>stub</em>.</p>
<p>We instantiate the <code>RouteGuideStub</code> class of the <code>route_guide_pb2_grpc</code>
module, generated from our .proto.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">channel <span style="color:#f92672">=</span> grpc<span style="color:#f92672">.</span>insecure_channel(<span style="color:#e6db74">&#39;localhost:50051&#39;</span>)
stub <span style="color:#f92672">=</span> route_guide_pb2_grpc<span style="color:#f92672">.</span>RouteGuideStub(channel)</code></pre></div>
<h4 id="calling-service-methods">Calling service methods</h4>
<p>For RPC methods that return a single response (&ldquo;response-unary&rdquo; methods), gRPC
Python supports both synchronous (blocking) and asynchronous (non-blocking)
control flow semantics. For response-streaming RPC methods, calls immediately
return an iterator of response values. Calls to that iterator&rsquo;s <code>next()</code> method
block until the response to be yielded from the iterator becomes available.</p>
<h5 id="simple-rpc-1">Simple RPC</h5>
<p>A synchronous call to the simple RPC <code>GetFeature</code> is nearly as straightforward
as calling a local method. The RPC call waits for the server to respond, and
will either return a response or raise an exception:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">feature <span style="color:#f92672">=</span> stub<span style="color:#f92672">.</span>GetFeature(point)</code></pre></div>
<p>An asynchronous call to <code>GetFeature</code> is similar, but like calling a local method
asynchronously in a thread pool:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">feature_future <span style="color:#f92672">=</span> stub<span style="color:#f92672">.</span>GetFeature<span style="color:#f92672">.</span>future(point)
feature <span style="color:#f92672">=</span> feature_future<span style="color:#f92672">.</span>result()</code></pre></div>
<h5 id="response-streaming-rpc-1">Response-streaming RPC</h5>
<p>Calling the response-streaming <code>ListFeatures</code> is similar to working with
sequence types:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">for</span> feature <span style="color:#f92672">in</span> stub<span style="color:#f92672">.</span>ListFeatures(rectangle):</code></pre></div>
<h5 id="request-streaming-rpc-1">Request-streaming RPC</h5>
<p>Calling the request-streaming <code>RecordRoute</code> is similar to passing an iterator
to a local method. Like the simple RPC above that also returns a single
response, it can be called synchronously or asynchronously:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">route_summary <span style="color:#f92672">=</span> stub<span style="color:#f92672">.</span>RecordRoute(point_iterator)</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">route_summary_future <span style="color:#f92672">=</span> stub<span style="color:#f92672">.</span>RecordRoute<span style="color:#f92672">.</span>future(point_iterator)
route_summary <span style="color:#f92672">=</span> route_summary_future<span style="color:#f92672">.</span>result()</code></pre></div>
<h5 id="bidirectional-streaming-rpc-1">Bidirectional streaming RPC</h5>
<p>Calling the bidirectionally-streaming <code>RouteChat</code> has (as is the case on the
service-side) a combination of the request-streaming and response-streaming
semantics:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">for</span> received_route_note <span style="color:#f92672">in</span> stub<span style="color:#f92672">.</span>RouteChat(sent_route_note_iterator):</code></pre></div>
<h3 id="try-it-out">Try it out!</h3>
<p>Run the server, which will listen on port 50051:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ python route_guide_server.py</code></pre></div>
<p>Run the client (in a different terminal):</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ python route_guide_client.py</code></pre></div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>