blob: c5f1ed806118c74cf904970d1201c6198a08bcb6 [file] [log] [blame]
Masood Malekghassemif8e297a2015-02-19 15:39:32 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Masood Malekghassemif8e297a2015-02-19 15:39:32 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -080034#include <algorithm>
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080035#include <cassert>
36#include <cctype>
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080037#include <cstring>
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080038#include <map>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070039#include <memory>
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080040#include <ostream>
41#include <sstream>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070042#include <tuple>
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080043#include <vector>
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080044
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070045#include "src/compiler/config.h"
Nicolas "Pixel" Noble93fa0982015-02-27 21:50:58 +010046#include "src/compiler/generator_helpers.h"
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080047#include "src/compiler/python_generator.h"
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080048
Nicolas "Pixel" Noble93fa0982015-02-27 21:50:58 +010049using grpc_generator::StringReplace;
50using grpc_generator::StripProto;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070051using grpc::protobuf::Descriptor;
52using grpc::protobuf::FileDescriptor;
53using grpc::protobuf::MethodDescriptor;
54using grpc::protobuf::ServiceDescriptor;
55using grpc::protobuf::compiler::GeneratorContext;
56using grpc::protobuf::io::CodedOutputStream;
57using grpc::protobuf::io::Printer;
58using grpc::protobuf::io::StringOutputStream;
59using grpc::protobuf::io::ZeroCopyOutputStream;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080060using std::initializer_list;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080061using std::make_pair;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080062using std::map;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080063using std::pair;
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -080064using std::replace;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080065using std::vector;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080066
67namespace grpc_python_generator {
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070068
Masood Malekghassemi71448b22016-06-29 11:41:24 -070069GeneratorConfiguration::GeneratorConfiguration()
70 : grpc_package_root("grpc"), beta_package_root("grpc.beta") {}
71
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070072PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
73 : config_(config) {}
74
75PythonGrpcGenerator::~PythonGrpcGenerator() {}
76
77bool PythonGrpcGenerator::Generate(
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070078 const FileDescriptor* file, const grpc::string& parameter,
79 GeneratorContext* context, grpc::string* error) const {
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070080 // Get output file name.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070081 grpc::string file_name;
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070082 static const int proto_suffix_length = strlen(".proto");
83 if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
84 file->name().find_last_of(".proto") == file->name().size() - 1) {
85 file_name = file->name().substr(
86 0, file->name().size() - proto_suffix_length) + "_pb2.py";
87 } else {
88 *error = "Invalid proto file name. Proto file must end with .proto";
89 return false;
90 }
91
92 std::unique_ptr<ZeroCopyOutputStream> output(
93 context->OpenForInsert(file_name, "module_scope"));
94 CodedOutputStream coded_out(output.get());
95 bool success = false;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070096 grpc::string code = "";
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070097 tie(success, code) = grpc_python_generator::GetServices(file, config_);
98 if (success) {
99 coded_out.WriteRaw(code.data(), code.size());
100 return true;
101 } else {
102 return false;
103 }
104}
105
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800106namespace {
107//////////////////////////////////
108// BEGIN FORMATTING BOILERPLATE //
109//////////////////////////////////
110
111// Converts an initializer list of the form { key0, value0, key1, value1, ... }
112// into a map of key* to value*. Is merely a readability helper for later code.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700113map<grpc::string, grpc::string> ListToDict(
114 const initializer_list<grpc::string>& values) {
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800115 assert(values.size() % 2 == 0);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700116 map<grpc::string, grpc::string> value_map;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800117 auto value_iter = values.begin();
118 for (unsigned i = 0; i < values.size()/2; ++i) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700119 grpc::string key = *value_iter;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800120 ++value_iter;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700121 grpc::string value = *value_iter;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800122 value_map[key] = value;
123 ++value_iter;
124 }
125 return value_map;
126}
127
128// Provides RAII indentation handling. Use as:
129// {
130// IndentScope raii_my_indent_var_name_here(my_py_printer);
131// // constructor indented my_py_printer
132// ...
133// // destructor called at end of scope, un-indenting my_py_printer
134// }
135class IndentScope {
136 public:
137 explicit IndentScope(Printer* printer) : printer_(printer) {
138 printer_->Indent();
139 }
140
141 ~IndentScope() {
142 printer_->Outdent();
143 }
144
145 private:
146 Printer* printer_;
147};
148
149////////////////////////////////
150// END FORMATTING BOILERPLATE //
151////////////////////////////////
152
Ken Paysonbe187b02016-05-06 15:32:58 -0700153// TODO(https://github.com/google/protobuf/issues/888):
154// Export `ModuleName` from protobuf's
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -0800155// `src/google/protobuf/compiler/python/python_generator.cc` file.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700156grpc::string ModuleName(const grpc::string& filename) {
157 grpc::string basename = StripProto(filename);
Nicolas "Pixel" Noble93fa0982015-02-27 21:50:58 +0100158 basename = StringReplace(basename, "-", "_");
159 basename = StringReplace(basename, "/", ".");
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -0800160 return basename + "_pb2";
161}
162
Ken Paysonbe187b02016-05-06 15:32:58 -0700163// TODO(https://github.com/google/protobuf/issues/888):
164// Export `ModuleAlias` from protobuf's
165// `src/google/protobuf/compiler/python/python_generator.cc` file.
166grpc::string ModuleAlias(const grpc::string& filename) {
167 grpc::string module_name = ModuleName(filename);
168 // We can't have dots in the module name, so we replace each with _dot_.
169 // But that could lead to a collision between a.b and a_dot_b, so we also
170 // duplicate each underscore.
171 module_name = StringReplace(module_name, "_", "__");
172 module_name = StringReplace(module_name, ".", "_dot_");
173 return module_name;
174}
175
176
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800177bool GetModuleAndMessagePath(const Descriptor* type,
Ken Paysonbe187b02016-05-06 15:32:58 -0700178 const ServiceDescriptor* service,
179 grpc::string* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800180 const Descriptor* path_elem_type = type;
181 vector<const Descriptor*> message_path;
182 do {
183 message_path.push_back(path_elem_type);
184 path_elem_type = path_elem_type->containing_type();
Vijay Paic0897432015-07-27 22:18:13 +0000185 } while (path_elem_type); // implicit nullptr comparison; don't be explicit
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700186 grpc::string file_name = type->file()->name();
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800187 static const int proto_suffix_length = strlen(".proto");
188 if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
189 file_name.find_last_of(".proto") == file_name.size() - 1)) {
190 return false;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800191 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700192 grpc::string service_file_name = service->file()->name();
193 grpc::string module = service_file_name == file_name ?
194 "" : ModuleAlias(file_name) + ".";
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700195 grpc::string message_type;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800196 for (auto path_iter = message_path.rbegin();
197 path_iter != message_path.rend(); ++path_iter) {
198 message_type += (*path_iter)->name() + ".";
199 }
Craig Tillercf133f42015-02-26 14:05:56 -0800200 // no pop_back prior to C++11
201 message_type.resize(message_type.size() - 1);
Ken Paysonbe187b02016-05-06 15:32:58 -0700202 *out = module + message_type;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800203 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800204}
205
yang-gb0de7162016-05-03 15:48:19 -0700206// Get all comments (leading, leading_detached, trailing) and print them as a
207// docstring. Any leading space of a line will be removed, but the line wrapping
208// will not be changed.
209template <typename DescriptorType>
210static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
211 std::vector<grpc::string> comments;
212 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
213 &comments);
214 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
215 &comments);
216 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
217 &comments);
218 if (comments.empty()) {
219 return;
220 }
221 printer->Print("\"\"\"");
222 for (auto it = comments.begin(); it != comments.end(); ++it) {
223 size_t start_pos = it->find_first_not_of(' ');
224 if (start_pos != grpc::string::npos) {
225 printer->Print(it->c_str() + start_pos);
226 }
227 printer->Print("\n");
228 }
229 printer->Print("\"\"\"\n");
230}
231
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000232bool PrintBetaServicer(const ServiceDescriptor* service,
233 Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700234 out->Print("\n\n");
yang-gb0de7162016-05-03 15:48:19 -0700235 out->Print("class Beta$Service$Servicer(object):\n", "Service",
236 service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000237 {
238 IndentScope raii_class_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700239 PrintAllComments(service, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000240 for (int i = 0; i < service->method_count(); ++i) {
241 auto meth = service->method(i);
242 grpc::string arg_name = meth->client_streaming() ?
243 "request_iterator" : "request";
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000244 out->Print("def $Method$(self, $ArgName$, context):\n",
245 "Method", meth->name(), "ArgName", arg_name);
246 {
247 IndentScope raii_method_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700248 PrintAllComments(meth, out);
Masood Malekghassemi832ae812016-04-27 18:38:54 -0700249 out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000250 }
251 }
252 }
253 return true;
254}
255
256bool PrintBetaStub(const ServiceDescriptor* service,
257 Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700258 out->Print("\n\n");
yang-gb0de7162016-05-03 15:48:19 -0700259 out->Print("class Beta$Service$Stub(object):\n", "Service", service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000260 {
261 IndentScope raii_class_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700262 PrintAllComments(service, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000263 for (int i = 0; i < service->method_count(); ++i) {
264 const MethodDescriptor* meth = service->method(i);
265 grpc::string arg_name = meth->client_streaming() ?
266 "request_iterator" : "request";
267 auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
Ken Paysonbe187b02016-05-06 15:32:58 -0700268 out->Print(methdict, "def $Method$(self, $ArgName$, timeout, metadata=None, with_call=False, protocol_options=None):\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000269 {
270 IndentScope raii_method_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700271 PrintAllComments(meth, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000272 out->Print("raise NotImplementedError()\n");
273 }
274 if (!meth->server_streaming()) {
275 out->Print(methdict, "$Method$.future = None\n");
276 }
277 }
278 }
279 return true;
280}
281
282bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
283 const ServiceDescriptor* service, Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700284 out->Print("\n\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000285 out->Print("def beta_create_$Service$_server(servicer, pool=None, "
286 "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
287 "Service", service->name());
288 {
289 IndentScope raii_create_server_indent(out);
290 map<grpc::string, grpc::string> method_implementation_constructors;
Ken Paysonbe187b02016-05-06 15:32:58 -0700291 map<grpc::string, grpc::string> input_message_modules_and_classes;
292 map<grpc::string, grpc::string> output_message_modules_and_classes;
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000293 for (int i = 0; i < service->method_count(); ++i) {
294 const MethodDescriptor* method = service->method(i);
295 const grpc::string method_implementation_constructor =
296 grpc::string(method->client_streaming() ? "stream_" : "unary_") +
297 grpc::string(method->server_streaming() ? "stream_" : "unary_") +
298 "inline";
Ken Paysonbe187b02016-05-06 15:32:58 -0700299 grpc::string input_message_module_and_class;
300 if (!GetModuleAndMessagePath(method->input_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000301 &input_message_module_and_class)) {
302 return false;
303 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700304 grpc::string output_message_module_and_class;
305 if (!GetModuleAndMessagePath(method->output_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000306 &output_message_module_and_class)) {
307 return false;
308 }
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000309 method_implementation_constructors.insert(
310 make_pair(method->name(), method_implementation_constructor));
311 input_message_modules_and_classes.insert(
312 make_pair(method->name(), input_message_module_and_class));
313 output_message_modules_and_classes.insert(
314 make_pair(method->name(), output_message_module_and_class));
315 }
316 out->Print("request_deserializers = {\n");
317 for (auto name_and_input_module_class_pair =
318 input_message_modules_and_classes.begin();
319 name_and_input_module_class_pair !=
320 input_message_modules_and_classes.end();
321 name_and_input_module_class_pair++) {
322 IndentScope raii_indent(out);
323 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
Ken Paysonbe187b02016-05-06 15:32:58 -0700324 "$InputTypeModuleAndClass$.FromString,\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000325 "PackageQualifiedServiceName", package_qualified_service_name,
326 "MethodName", name_and_input_module_class_pair->first,
Ken Paysonbe187b02016-05-06 15:32:58 -0700327 "InputTypeModuleAndClass",
328 name_and_input_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000329 }
330 out->Print("}\n");
331 out->Print("response_serializers = {\n");
332 for (auto name_and_output_module_class_pair =
333 output_message_modules_and_classes.begin();
334 name_and_output_module_class_pair !=
335 output_message_modules_and_classes.end();
336 name_and_output_module_class_pair++) {
337 IndentScope raii_indent(out);
338 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
Ken Paysonbe187b02016-05-06 15:32:58 -0700339 "$OutputTypeModuleAndClass$.SerializeToString,\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000340 "PackageQualifiedServiceName", package_qualified_service_name,
341 "MethodName", name_and_output_module_class_pair->first,
Ken Paysonbe187b02016-05-06 15:32:58 -0700342 "OutputTypeModuleAndClass",
343 name_and_output_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000344 }
345 out->Print("}\n");
346 out->Print("method_implementations = {\n");
347 for (auto name_and_implementation_constructor =
Nathaniel Manista45479402016-06-13 20:14:18 +0000348 method_implementation_constructors.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000349 name_and_implementation_constructor !=
350 method_implementation_constructors.end();
351 name_and_implementation_constructor++) {
352 IndentScope raii_descriptions_indent(out);
353 const grpc::string method_name =
354 name_and_implementation_constructor->first;
355 out->Print("(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
356 "face_utilities.$Constructor$(servicer.$Method$),\n",
357 "PackageQualifiedServiceName", package_qualified_service_name,
358 "Method", name_and_implementation_constructor->first,
359 "Constructor", name_and_implementation_constructor->second);
360 }
361 out->Print("}\n");
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000362 out->Print("server_options = beta_implementations.server_options("
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000363 "request_deserializers=request_deserializers, "
364 "response_serializers=response_serializers, "
365 "thread_pool=pool, thread_pool_size=pool_size, "
366 "default_timeout=default_timeout, "
367 "maximum_timeout=maximum_timeout)\n");
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000368 out->Print("return beta_implementations.server(method_implementations, "
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000369 "options=server_options)\n");
370 }
371 return true;
372}
373
374bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
375 const ServiceDescriptor* service, Printer* out) {
376 map<grpc::string, grpc::string> dict = ListToDict({
377 "Service", service->name(),
378 });
Ken Paysonbe187b02016-05-06 15:32:58 -0700379 out->Print("\n\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000380 out->Print(dict, "def beta_create_$Service$_stub(channel, host=None,"
381 " metadata_transformer=None, pool=None, pool_size=None):\n");
382 {
383 IndentScope raii_create_server_indent(out);
384 map<grpc::string, grpc::string> method_cardinalities;
Ken Paysonbe187b02016-05-06 15:32:58 -0700385 map<grpc::string, grpc::string> input_message_modules_and_classes;
386 map<grpc::string, grpc::string> output_message_modules_and_classes;
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000387 for (int i = 0; i < service->method_count(); ++i) {
388 const MethodDescriptor* method = service->method(i);
389 const grpc::string method_cardinality =
390 grpc::string(method->client_streaming() ? "STREAM" : "UNARY") +
391 "_" +
Ken Paysonbe187b02016-05-06 15:32:58 -0700392 grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
393 grpc::string input_message_module_and_class;
394 if (!GetModuleAndMessagePath(method->input_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000395 &input_message_module_and_class)) {
396 return false;
397 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700398 grpc::string output_message_module_and_class;
399 if (!GetModuleAndMessagePath(method->output_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000400 &output_message_module_and_class)) {
401 return false;
402 }
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000403 method_cardinalities.insert(
404 make_pair(method->name(), method_cardinality));
405 input_message_modules_and_classes.insert(
406 make_pair(method->name(), input_message_module_and_class));
407 output_message_modules_and_classes.insert(
408 make_pair(method->name(), output_message_module_and_class));
409 }
410 out->Print("request_serializers = {\n");
411 for (auto name_and_input_module_class_pair =
412 input_message_modules_and_classes.begin();
413 name_and_input_module_class_pair !=
414 input_message_modules_and_classes.end();
415 name_and_input_module_class_pair++) {
416 IndentScope raii_indent(out);
417 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
Ken Paysonbe187b02016-05-06 15:32:58 -0700418 "$InputTypeModuleAndClass$.SerializeToString,\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000419 "PackageQualifiedServiceName", package_qualified_service_name,
420 "MethodName", name_and_input_module_class_pair->first,
Ken Paysonbe187b02016-05-06 15:32:58 -0700421 "InputTypeModuleAndClass",
422 name_and_input_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000423 }
424 out->Print("}\n");
425 out->Print("response_deserializers = {\n");
426 for (auto name_and_output_module_class_pair =
427 output_message_modules_and_classes.begin();
428 name_and_output_module_class_pair !=
429 output_message_modules_and_classes.end();
430 name_and_output_module_class_pair++) {
431 IndentScope raii_indent(out);
432 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
Ken Paysonbe187b02016-05-06 15:32:58 -0700433 "$OutputTypeModuleAndClass$.FromString,\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000434 "PackageQualifiedServiceName", package_qualified_service_name,
435 "MethodName", name_and_output_module_class_pair->first,
Ken Paysonbe187b02016-05-06 15:32:58 -0700436 "OutputTypeModuleAndClass",
437 name_and_output_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000438 }
439 out->Print("}\n");
440 out->Print("cardinalities = {\n");
441 for (auto name_and_cardinality = method_cardinalities.begin();
442 name_and_cardinality != method_cardinalities.end();
443 name_and_cardinality++) {
444 IndentScope raii_descriptions_indent(out);
445 out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
446 "Method", name_and_cardinality->first,
447 "Cardinality", name_and_cardinality->second);
448 }
449 out->Print("}\n");
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000450 out->Print("stub_options = beta_implementations.stub_options("
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000451 "host=host, metadata_transformer=metadata_transformer, "
452 "request_serializers=request_serializers, "
453 "response_deserializers=response_deserializers, "
454 "thread_pool=pool, thread_pool_size=pool_size)\n");
455 out->Print(
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000456 "return beta_implementations.dynamic_stub(channel, \'$PackageQualifiedServiceName$\', "
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000457 "cardinalities, options=stub_options)\n",
458 "PackageQualifiedServiceName", package_qualified_service_name);
459 }
460 return true;
461}
462
Nathaniel Manista45479402016-06-13 20:14:18 +0000463bool PrintStub(const grpc::string& package_qualified_service_name,
464 const ServiceDescriptor* service, Printer* out) {
465 out->Print("\n\n");
466 out->Print("class $Service$Stub(object):\n", "Service", service->name());
467 {
468 IndentScope raii_class_indent(out);
469 PrintAllComments(service, out);
470 out->Print("\n");
471 out->Print("def __init__(self, channel):\n");
472 {
473 IndentScope raii_init_indent(out);
474 out->Print("\"\"\"Constructor.\n");
475 out->Print("\n");
476 out->Print("Args:\n");
477 {
478 IndentScope raii_args_indent(out);
479 out->Print("channel: A grpc.Channel.\n");
480 }
481 out->Print("\"\"\"\n");
482 for (int i = 0; i < service->method_count(); ++i) {
483 auto method = service->method(i);
484 auto multi_callable_constructor =
485 grpc::string(method->client_streaming() ? "stream" : "unary") +
486 "_" +
487 grpc::string(method->server_streaming() ? "stream" : "unary");
488 grpc::string request_module_and_class;
489 if (!GetModuleAndMessagePath(method->input_type(), service,
490 &request_module_and_class)) {
491 return false;
492 }
493 grpc::string response_module_and_class;
494 if (!GetModuleAndMessagePath(method->output_type(), service,
495 &response_module_and_class)) {
496 return false;
497 }
498 out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
499 "Method", method->name(),
500 "MultiCallableConstructor", multi_callable_constructor);
501 {
502 IndentScope raii_first_attribute_indent(out);
503 IndentScope raii_second_attribute_indent(out);
504 out->Print(
505 "'/$PackageQualifiedService$/$Method$',\n",
506 "PackageQualifiedService", package_qualified_service_name,
507 "Method", method->name());
508 out->Print(
509 "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
510 "RequestModuleAndClass", request_module_and_class);
511 out->Print(
512 "response_deserializer=$ResponseModuleAndClass$.FromString,\n",
513 "ResponseModuleAndClass", response_module_and_class);
514 out->Print(")\n");
515 }
516 }
517 }
518 }
519 return true;
520}
521
522bool PrintServicer(const ServiceDescriptor* service, Printer* out) {
523 out->Print("\n\n");
524 out->Print("class $Service$Servicer(object):\n", "Service", service->name());
525 {
526 IndentScope raii_class_indent(out);
527 PrintAllComments(service, out);
528 for (int i = 0; i < service->method_count(); ++i) {
529 auto method = service->method(i);
530 grpc::string arg_name = method->client_streaming() ?
531 "request_iterator" : "request";
532 out->Print("\n");
533 out->Print("def $Method$(self, $ArgName$, context):\n",
534 "Method", method->name(), "ArgName", arg_name);
535 {
536 IndentScope raii_method_indent(out);
537 PrintAllComments(method, out);
538 out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n");
539 out->Print("context.set_details('Method not implemented!')\n");
540 out->Print("raise NotImplementedError('Method not implemented!')\n");
541 }
542 }
543 }
544 return true;
545}
546
547bool PrintAddServicerToServer(const grpc::string& package_qualified_service_name,
548 const ServiceDescriptor* service, Printer* out) {
549 out->Print("\n\n");
550 out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
551 "Service", service->name());
552 {
553 IndentScope raii_class_indent(out);
554 out->Print("rpc_method_handlers = {\n");
555 {
556 IndentScope raii_dict_first_indent(out);
557 IndentScope raii_dict_second_indent(out);
558 for (int i = 0; i < service->method_count(); ++i) {
559 auto method = service->method(i);
560 auto method_handler_constructor =
561 grpc::string(method->client_streaming() ? "stream" : "unary") +
562 "_" +
563 grpc::string(method->server_streaming() ? "stream" : "unary") +
564 "_rpc_method_handler";
565 grpc::string request_module_and_class;
566 if (!GetModuleAndMessagePath(method->input_type(), service,
567 &request_module_and_class)) {
568 return false;
569 }
570 grpc::string response_module_and_class;
571 if (!GetModuleAndMessagePath(method->output_type(), service,
572 &response_module_and_class)) {
573 return false;
574 }
575 out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n",
576 "Method", method->name(),
577 "MethodHandlerConstructor", method_handler_constructor);
578 {
579 IndentScope raii_call_first_indent(out);
580 IndentScope raii_call_second_indent(out);
581 out->Print("servicer.$Method$,\n", "Method", method->name());
582 out->Print("request_deserializer=$RequestModuleAndClass$.FromString,\n",
583 "RequestModuleAndClass", request_module_and_class);
584 out->Print("response_serializer=$ResponseModuleAndClass$.SerializeToString,\n",
585 "ResponseModuleAndClass", response_module_and_class);
586 }
587 out->Print("),\n");
588 }
589 }
590 out->Print("}\n");
591 out->Print("generic_handler = grpc.method_handlers_generic_handler(\n");
592 {
593 IndentScope raii_call_first_indent(out);
594 IndentScope raii_call_second_indent(out);
595 out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
596 "PackageQualifiedServiceName", package_qualified_service_name);
597 }
598 out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
599 }
600 return true;
601}
602
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700603bool PrintPreamble(const FileDescriptor* file,
604 const GeneratorConfiguration& config, Printer* out) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000605 out->Print("import $Package$\n", "Package", config.grpc_package_root);
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000606 out->Print("from $Package$ import implementations as beta_implementations\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000607 "Package", config.beta_package_root);
Masood Malekghassemi832ae812016-04-27 18:38:54 -0700608 out->Print("from $Package$ import interfaces as beta_interfaces\n",
609 "Package", config.beta_package_root);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000610 out->Print("from grpc.framework.common import cardinality\n");
611 out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800612 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800613}
614
615} // namespace
616
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700617pair<bool, grpc::string> GetServices(const FileDescriptor* file,
Nathaniel Manistadc8c3232016-01-16 18:28:45 +0000618 const GeneratorConfiguration& config) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700619 grpc::string output;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800620 {
621 // Scope the output stream so it closes and finalizes output to the string.
622 StringOutputStream output_stream(&output);
623 Printer out(&output_stream, '$');
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700624 if (!PrintPreamble(file, config, &out)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800625 return make_pair(false, "");
626 }
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000627 auto package = file->package();
628 if (!package.empty()) {
629 package = package.append(".");
630 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800631 for (int i = 0; i < file->service_count(); ++i) {
632 auto service = file->service(i);
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000633 auto package_qualified_service_name = package + service->name();
Nathaniel Manista45479402016-06-13 20:14:18 +0000634 if (!(PrintStub(package_qualified_service_name, service, &out) &&
635 PrintServicer(service, &out) &&
636 PrintAddServicerToServer(package_qualified_service_name, service, &out) &&
637 PrintBetaServicer(service, &out) &&
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000638 PrintBetaStub(service, &out) &&
639 PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
640 PrintBetaStubFactory(package_qualified_service_name, service, &out))) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800641 return make_pair(false, "");
642 }
643 }
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800644 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800645 return make_pair(true, std::move(output));
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800646}
647
648} // namespace grpc_python_generator