|
1 | 1 | # Getting Started with gRPC-Python |
2 | 2 |
|
3 | | -Get hands-on with gRPC for Python in this interactive codelab! |
| 3 | +Get hands-on with gRPC for Python in this interactive codelab! |
4 | 4 |
|
5 | 5 | Perfect for Python developers new to gRPC, those seeking a refresher, or anyone building distributed |
6 | 6 | systems. No prior gRPC experience needed! |
7 | 7 |
|
8 | | -**Build a complete gRPC service from scratch, learning:** |
9 | | - |
10 | | -- Protocol Buffers (protobuf): Define service contracts & data. |
11 | | -- gRPC Code Generation: Auto-generate Python code. |
12 | | -- Client/Server Communication: Implement seamless interactions. |
13 | | - |
14 | | -**You'll gain:** |
15 | | - |
16 | | -- A working gRPC service in Python. |
17 | | -- Hands-on experience with Protocol Buffers and code generation. |
18 | | -- Skills to design, build, & test gRPC clients and servers. |
19 | | -- A strong foundation in gRPC for real-world projects. |
20 | | - |
21 | 8 | ### How to use this directory |
22 | 9 |
|
23 | | -- [start_here](./start_here/) directory serves as a starting point for the codelab. |
| 10 | +- [start_here](./start_here/) directory serves as a starting point for the codelab. |
24 | 11 | - [completed](./completed/) directory showcases the finished code, giving you a peak of how the |
25 | 12 | final implementation should look like. |
26 | 13 |
|
27 | | -## Prerequisites |
28 | | - |
29 | | -### This codelab |
30 | | - |
31 | | -```sh |
32 | | -cd ~/your-dev-dir |
33 | | -git clone https://github.com/grpc-ecosystem/grpc-codelabs.git |
34 | | -cd grpc-codelabs/ |
35 | | -``` |
36 | | - |
37 | | -### Python3 |
38 | | - |
39 | | -For this codelab, we require python 3.9 or higher, but recommend python 3.11. System-specific |
40 | | -instructions can be found in Python documentation: [Python Setup and Usage](https://docs.python.org/3/using/index.html). |
41 | | - |
42 | | -### Pip3 |
43 | | - |
44 | | -We recommend using the latest pip, see [Installation - pip](https://pip.pypa.io/en/stable/installation/). |
45 | | -In some OS distributions, `ensurepip` is not available out-of-box. On Debian/Ubuntu, you may need |
46 | | -to run. |
47 | | - |
48 | | -```sh |
49 | | -sudo apt-get install python3-pip |
50 | | -``` |
51 | | - |
52 | | -If necessary, upgrade your version of pip: |
53 | | - |
54 | | -```sh |
55 | | -python3 -m ensurepip --upgrade |
56 | | -``` |
57 | | - |
58 | | -If your python installation is owned by the system, pip will be installed in the user directory. If |
59 | | -you may see a warning like this, ensure the pip directory is in `$PATH`: |
60 | | - |
61 | | -``` |
62 | | -WARNING: The scripts pip3 and pip3.9 are installed in '/Users/sergiitk/Library/Python/3.9/bin' which is not on PATH. |
63 | | -Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. |
64 | | -``` |
65 | | - |
66 | | -### Venv |
67 | | - |
68 | | -[venv](https://docs.python.org/3/library/venv.html) is a built-in tool to create python virtual |
69 | | -environments. However, some OS distributions choose to exclude it. You can check if it's available |
70 | | -on your system with |
71 | | - |
72 | | -```sh |
73 | | -python3 -m venv --help |
74 | | -``` |
75 | | - |
76 | | -In debian/ubuntu, this also will advise you on what package to install. You may need to run |
77 | | -something like this: |
78 | | - |
79 | | -```sh |
80 | | -sudo apt-get install python3-venv |
81 | | -``` |
82 | | - |
83 | | -Once `venv` is installed, create a virtual environment: |
84 | | - |
85 | | -```sh |
86 | | -cd codelabs/grpc-python-getting-started |
87 | | -python3 -m venv .venv |
88 | | -``` |
89 | | - |
90 | | -#### Activate virtual environment |
91 | | - |
92 | | -```sh |
93 | | -cd "$(git rev-parse --show-toplevel || echo .)" && cd codelabs/grpc-python-getting-started |
94 | | -source ./.venv/bin/activate |
95 | | -``` |
96 | | - |
97 | | -## Define proto |
98 | | - |
99 | | -Your working directory will be `codelabs/grpc-python-getting-started/start_here`. Assuming you |
100 | | -followed `venv` activation section, you can cd into the start folder with: |
101 | | - |
102 | | -```sh |
103 | | -cd start_here/ |
104 | | -``` |
105 | | - |
106 | | -Our first step is to define the gRPC *service* and the method *request* and *response* types using |
107 | | -[protocol buffers](https://protobuf.dev/overview). |
108 | | - |
109 | | -Let’s start by defining the messages and service in `route_guide.proto`. |
110 | | - |
111 | | -### Define Proto Messages |
112 | | - |
113 | | -Our `.proto` file contains protocol buffer message type definitions for all the request and response |
114 | | -types used in our service methods. |
115 | | - |
116 | | -Let’s define the `Point` message type: |
117 | | - |
118 | | -```proto |
119 | | -message Point { |
120 | | - int32 latitude = 1; |
121 | | - int32 longitude = 2; |
122 | | -} |
123 | | -``` |
124 | | - |
125 | | -Let’s also define the `Feature` message type: |
126 | | - |
127 | | -```proto |
128 | | -message Feature { |
129 | | - // The name of the feature. |
130 | | - string name = 1; |
131 | | -
|
132 | | - // The point where the feature is detected. |
133 | | - Point location = 2; |
134 | | -} |
135 | | -``` |
136 | | - |
137 | | -### Define RouteGuide Service |
138 | | - |
139 | | -To define a service, you specify a named `service` in your `.proto` file: |
140 | | - |
141 | | -```proto |
142 | | -service RouteGuide { |
143 | | - // Definition of the service goes here |
144 | | -} |
145 | | -``` |
146 | | - |
147 | | -### Define RPC Method |
148 | | - |
149 | | -Then you define `rpc` methods inside your service definition, specifying their request and response |
150 | | -types. In this section of the codelab, let’s define a Unary RPC method. |
151 | | - |
152 | | -> Unary RPC method - A *simple RPC* where the client sends a request to the server using the stub |
153 | | - and waits for a response to come back, just like a normal function call. |
154 | | - |
155 | | -```proto |
156 | | -// Obtains the feature at a given position. |
157 | | -rpc GetFeature(Point) returns (Feature) {} |
158 | | -``` |
159 | | - |
160 | | -> [!TIP] |
161 | | -> For the complete .proto file, see |
162 | | -> [`completed/protos/route_guide.proto`](https://github.com/grpc-ecosystem/grpc-codelabs/blob/main/codelabs/grpc-python-getting-started/completed/protos/route_guide.proto) |
163 | | -
|
164 | | -## Generating client and server code |
165 | | - |
166 | | -Next you need to generate the gRPC client and server interfaces from your .proto service definition. |
167 | | - |
168 | | -First, install the grpcio-tools package: |
169 | | - |
170 | | -```sh |
171 | | -pip install --require-virtualenv grpcio-tools |
172 | | -``` |
173 | | - |
174 | | -If you see `ERROR: Could not find an activated virtualenv (required)`, please |
175 | | -[activate virtual environment](#activate-virtual-environment), then cd into `start_here`. |
176 | | - |
177 | | -Use the following command to generate the Python code: |
178 | | - |
179 | | -```sh |
180 | | -python -m grpc_tools.protoc --proto_path=./protos \ |
181 | | - --python_out=. --pyi_out=. --grpc_python_out=. \ |
182 | | - ./protos/route_guide.proto |
183 | | -``` |
184 | | - |
185 | | -Note that as we’ve already provided a version of the generated code in the `completed` directory, |
186 | | -running this command regenerates the appropriate file rather than creating a new one. The generated |
187 | | -code files are called `route_guide_pb2.py` and `route_guide_pb2_grpc.py` and contain: |
188 | | - |
189 | | -* classes for the messages defined in `route_guide.proto` |
190 | | -* classes for the service defined in `route_guide.proto` |
191 | | - * `RouteGuideStub`, which can be used by clients to invoke RouteGuide RPCs |
192 | | - * `RouteGuideServicer`, which defines the interface for implementations of the RouteGuide service |
193 | | -* a function for the service defined in `route_guide.proto` |
194 | | - * `add_RouteGuideServicer_to_server`, which adds a RouteGuideServicer to a `grpc.Server`. |
195 | | - |
196 | | -> [!Note] |
197 | | -> The `2` in pb2 indicates that the generated code is following Protocol Buffers Python API version |
198 | | -> 2. Version 1 is obsolete. It has no relation to the Protocol Buffers Language version, which is |
199 | | -> the one indicated by `syntax = "proto3"` or `syntax = "proto2"` in a `.proto` file. |
200 | | -
|
201 | | - |
202 | | -## Creating the server |
203 | | - |
204 | | -First let’s look at how you create a `RouteGuide` server. Creating and running a `RouteGuide` server |
205 | | -breaks down into two work items: |
206 | | - |
207 | | -* Implementing the servicer interface generated from our service definition with functions that |
208 | | - perform the actual “work” of the service. |
209 | | -* Running a gRPC server to listen for requests from clients and transmit responses. |
210 | | - |
211 | | -You can find the initial `RouteGuide` server in [`start_here/route_guide_server.py`](https://github.com/grpc-ecosystem/grpc-codelabs/blob/main/codelabs/grpc-python-getting-started/start_here/route_guide_server.py). |
212 | | - |
213 | | -### Implementing RouteGuide |
214 | | - |
215 | | -`route_guide_server.py` has a `RouteGuideServicer` class that subclasses the generated class |
216 | | -`route_guide_pb2_grpc.RouteGuideServicer`: |
217 | | - |
218 | | -```py |
219 | | -# RouteGuideServicer provides an implementation |
220 | | -# of the methods of the RouteGuide service. |
221 | | -class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer): |
222 | | -``` |
223 | | - |
224 | | -`RouteGuideServicer` implements all the `RouteGuide` service methods. |
225 | | - |
226 | | -Let us look into a simple RPC implementation in detail. Method `GetFeature` gets a `Point` from the |
227 | | -client and returns the corresponding feature information from its database in `Feature`. |
228 | | - |
229 | | -```py |
230 | | -def GetFeature(self, request, context): |
231 | | - feature = get_feature(self.db, request) |
232 | | - if feature is None: |
233 | | - return route_guide_pb2.Feature(name="", location=request) |
234 | | - else: |
235 | | - return feature |
236 | | -``` |
237 | | - |
238 | | -The method is passed a `route_guide_pb2.Point` request for the RPC, and a `grpc.ServicerContext` |
239 | | -object that provides RPC-specific information such as timeout limits. It returns a |
240 | | -`route_guide_pb2.Feature` response. |
241 | | - |
242 | | -> [!TIP] |
243 | | -> For the completed route guide server, see |
244 | | -> [`completed/route_guide_server.py`](https://github.com/grpc-ecosystem/grpc-codelabs/blob/main/codelabs/grpc-python-getting-started/completed/route_guide_server.py). |
245 | | -
|
246 | | -## Starting the server |
247 | | - |
248 | | -Once you have implemented all the `RouteGuide` methods, the next step is to start up a gRPC server |
249 | | -so that clients can actually use your service: |
250 | | - |
251 | | -```py |
252 | | -def serve(): |
253 | | - server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) |
254 | | - route_guide_pb2_grpc.add_RouteGuideServicer_to_server(RouteGuideServicer(), server) |
255 | | - listen_addr = "localhost:50051" |
256 | | - server.add_insecure_port(listen_addr) |
257 | | - print(f"Starting server on {listen_addr}") |
258 | | - server.start() |
259 | | - server.wait_for_termination() |
260 | | -``` |
261 | | - |
262 | | -The server `start()` method is non-blocking. A new thread will be instantiated to handle requests. |
263 | | -The thread calling `server.start()` will often not have any other work to do in the meantime. In |
264 | | -this case, you can call `server.wait_for_termination()` to cleanly block the calling thread until |
265 | | -the server terminates. |
266 | | - |
267 | | -> [!TIP] |
268 | | -> For the completed route guide server, see |
269 | | -> [`completed/route_guide_server.py`](https://github.com/grpc-ecosystem/grpc-codelabs/blob/main/codelabs/grpc-python-getting-started/completed/route_guide_server.py). |
270 | | -
|
271 | | -## Creating the client |
272 | | - |
273 | | -In this section, we’ll look at creating a client for our `RouteGuide` service. You can see the |
274 | | -initial client code in [`start_here/route_guide_client.py`](https://github.com/grpc-ecosystem/grpc-codelabs/blob/main/codelabs/grpc-python-getting-started/start_here/route_guide_client.py). |
275 | | - |
276 | | -### Creating a stub |
277 | | - |
278 | | -To call service methods, we first need to create a *stub*. |
279 | | - |
280 | | -We instantiate the `RouteGuideStub` class of the `route_guide_pb2_grpc` module, generated from our |
281 | | -`.proto` inside of the `route_guide_client.py` file. |
282 | | - |
283 | | -```py |
284 | | -channel = grpc.insecure_channel('localhost:50051') |
285 | | -stub = route_guide_pb2_grpc.RouteGuideStub(channel) |
286 | | -``` |
287 | | - |
288 | | -### Calling service methods |
289 | | - |
290 | | -For RPC methods that return a single response (“response-unary” methods), gRPC Python supports both |
291 | | -synchronous (blocking) and asynchronous (non-blocking) control flow semantics. |
292 | | - |
293 | | -### Simple RPC |
294 | | - |
295 | | -First, let's define a `Point` to call the service with. This should be as simple as instantiating an |
296 | | -object from the `route_guide_pb2` package with some properties: |
297 | | - |
298 | | -```py |
299 | | -point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814) |
300 | | -``` |
301 | | - |
302 | | -A synchronous call to the simple RPC `GetFeature` is nearly as straightforward as calling a local |
303 | | -method. The RPC call waits for the server to respond, and will either return a response or raise an |
304 | | -exception. We can call the method and see the response like this: |
305 | | - |
306 | | -```py |
307 | | -feature = stub.GetFeature(point) |
308 | | -print(feature) |
309 | | -``` |
310 | | - |
311 | | -You can inspect the fields of the Feature object and output the result of the request: |
312 | | - |
313 | | -```py |
314 | | -if feature.name: |
315 | | - print(f"Feature called '{feature.name}' at {format_point(feature.location)}") |
316 | | -else: |
317 | | - print(f"Found no feature at at {format_point(feature.location)}") |
318 | | -``` |
319 | | - |
320 | | -> [!TIP] |
321 | | -> For the completed route guide client, see |
322 | | -> [`completed/route_guide_client.py`](https://github.com/grpc-ecosystem/grpc-codelabs/blob/main/codelabs/grpc-python-getting-started/completed/route_guide_client.py). |
323 | | -
|
324 | | -## Try it out! |
325 | | - |
326 | | -Run the server: |
327 | | - |
328 | | -```sh |
329 | | -python route_guide_server.py |
330 | | -``` |
331 | | - |
332 | | -From a different terminal, [activate virtual environment](#activate-virtual-environment), then run |
333 | | -the client: |
334 | | - |
335 | | -```sh |
336 | | -python route_guide_client.py |
337 | | -``` |
338 | | - |
339 | | -## What’s next |
| 14 | +## Codelab |
340 | 15 |
|
341 | | -* Learn how gRPC works in [Introduction to gRPC](https://grpc.io/docs/what-is-grpc/introduction/) |
342 | | - and [Core concepts](https://grpc.io/docs/what-is-grpc/core-concepts/). |
343 | | -* Explore the [Python API reference](https://grpc.github.io/grpc/python/). |
| 16 | +Follow the codelab at: |
| 17 | +https://codelabs.developers.google.com/grpc/getting-started-grpc-python |
0 commit comments