blob: 0f61b1fb6c03c9d5eb651d9a5178d12d32fc5411 [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
Masood Malekghassemiac592452016-07-01 11:58:04 -070077bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
78 const grpc::string& parameter,
79 GeneratorContext* context,
80 grpc::string* error) const {
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070081 // Get output file name.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070082 grpc::string file_name;
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070083 static const int proto_suffix_length = strlen(".proto");
84 if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
85 file->name().find_last_of(".proto") == file->name().size() - 1) {
Masood Malekghassemiac592452016-07-01 11:58:04 -070086 file_name =
87 file->name().substr(0, file->name().size() - proto_suffix_length) +
88 "_pb2.py";
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070089 } else {
90 *error = "Invalid proto file name. Proto file must end with .proto";
91 return false;
92 }
93
94 std::unique_ptr<ZeroCopyOutputStream> output(
95 context->OpenForInsert(file_name, "module_scope"));
96 CodedOutputStream coded_out(output.get());
97 bool success = false;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070098 grpc::string code = "";
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070099 tie(success, code) = grpc_python_generator::GetServices(file, config_);
100 if (success) {
101 coded_out.WriteRaw(code.data(), code.size());
102 return true;
103 } else {
104 return false;
105 }
106}
107
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800108namespace {
109//////////////////////////////////
110// BEGIN FORMATTING BOILERPLATE //
111//////////////////////////////////
112
113// Converts an initializer list of the form { key0, value0, key1, value1, ... }
114// into a map of key* to value*. Is merely a readability helper for later code.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700115map<grpc::string, grpc::string> ListToDict(
116 const initializer_list<grpc::string>& values) {
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800117 assert(values.size() % 2 == 0);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700118 map<grpc::string, grpc::string> value_map;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800119 auto value_iter = values.begin();
Masood Malekghassemiac592452016-07-01 11:58:04 -0700120 for (unsigned i = 0; i < values.size() / 2; ++i) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700121 grpc::string key = *value_iter;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800122 ++value_iter;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700123 grpc::string value = *value_iter;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800124 value_map[key] = value;
125 ++value_iter;
126 }
127 return value_map;
128}
129
130// Provides RAII indentation handling. Use as:
131// {
132// IndentScope raii_my_indent_var_name_here(my_py_printer);
133// // constructor indented my_py_printer
134// ...
135// // destructor called at end of scope, un-indenting my_py_printer
136// }
137class IndentScope {
138 public:
139 explicit IndentScope(Printer* printer) : printer_(printer) {
140 printer_->Indent();
141 }
142
Masood Malekghassemiac592452016-07-01 11:58:04 -0700143 ~IndentScope() { printer_->Outdent(); }
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800144
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
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800176bool GetModuleAndMessagePath(const Descriptor* type,
Ken Paysonbe187b02016-05-06 15:32:58 -0700177 const ServiceDescriptor* service,
178 grpc::string* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800179 const Descriptor* path_elem_type = type;
180 vector<const Descriptor*> message_path;
181 do {
182 message_path.push_back(path_elem_type);
183 path_elem_type = path_elem_type->containing_type();
Masood Malekghassemiac592452016-07-01 11:58:04 -0700184 } while (path_elem_type); // implicit nullptr comparison; don't be explicit
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700185 grpc::string file_name = type->file()->name();
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800186 static const int proto_suffix_length = strlen(".proto");
187 if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
188 file_name.find_last_of(".proto") == file_name.size() - 1)) {
189 return false;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800190 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700191 grpc::string service_file_name = service->file()->name();
Masood Malekghassemiac592452016-07-01 11:58:04 -0700192 grpc::string module =
193 service_file_name == file_name ? "" : ModuleAlias(file_name) + ".";
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700194 grpc::string message_type;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700195 for (auto path_iter = message_path.rbegin(); path_iter != message_path.rend();
196 ++path_iter) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800197 message_type += (*path_iter)->name() + ".";
198 }
Craig Tillercf133f42015-02-26 14:05:56 -0800199 // no pop_back prior to C++11
200 message_type.resize(message_type.size() - 1);
Ken Paysonbe187b02016-05-06 15:32:58 -0700201 *out = module + message_type;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800202 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800203}
204
yang-gb0de7162016-05-03 15:48:19 -0700205// Get all comments (leading, leading_detached, trailing) and print them as a
206// docstring. Any leading space of a line will be removed, but the line wrapping
207// will not be changed.
208template <typename DescriptorType>
209static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
210 std::vector<grpc::string> comments;
211 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
212 &comments);
213 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
214 &comments);
215 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
216 &comments);
217 if (comments.empty()) {
218 return;
219 }
220 printer->Print("\"\"\"");
221 for (auto it = comments.begin(); it != comments.end(); ++it) {
222 size_t start_pos = it->find_first_not_of(' ');
223 if (start_pos != grpc::string::npos) {
224 printer->Print(it->c_str() + start_pos);
225 }
226 printer->Print("\n");
227 }
228 printer->Print("\"\"\"\n");
229}
230
Masood Malekghassemiac592452016-07-01 11:58:04 -0700231bool PrintBetaServicer(const ServiceDescriptor* service, Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700232 out->Print("\n\n");
yang-gb0de7162016-05-03 15:48:19 -0700233 out->Print("class Beta$Service$Servicer(object):\n", "Service",
234 service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000235 {
236 IndentScope raii_class_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700237 PrintAllComments(service, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000238 for (int i = 0; i < service->method_count(); ++i) {
239 auto meth = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700240 grpc::string arg_name =
241 meth->client_streaming() ? "request_iterator" : "request";
242 out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
243 meth->name(), "ArgName", arg_name);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000244 {
245 IndentScope raii_method_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700246 PrintAllComments(meth, out);
Masood Malekghassemi832ae812016-04-27 18:38:54 -0700247 out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000248 }
249 }
250 }
251 return true;
252}
253
Masood Malekghassemiac592452016-07-01 11:58:04 -0700254bool PrintBetaStub(const ServiceDescriptor* service, Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700255 out->Print("\n\n");
yang-gb0de7162016-05-03 15:48:19 -0700256 out->Print("class Beta$Service$Stub(object):\n", "Service", service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000257 {
258 IndentScope raii_class_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700259 PrintAllComments(service, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000260 for (int i = 0; i < service->method_count(); ++i) {
261 const MethodDescriptor* meth = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700262 grpc::string arg_name =
263 meth->client_streaming() ? "request_iterator" : "request";
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000264 auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
Masood Malekghassemiac592452016-07-01 11:58:04 -0700265 out->Print(methdict,
266 "def $Method$(self, $ArgName$, timeout, metadata=None, "
267 "with_call=False, protocol_options=None):\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000268 {
269 IndentScope raii_method_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700270 PrintAllComments(meth, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000271 out->Print("raise NotImplementedError()\n");
272 }
273 if (!meth->server_streaming()) {
274 out->Print(methdict, "$Method$.future = None\n");
275 }
276 }
277 }
278 return true;
279}
280
281bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
282 const ServiceDescriptor* service, Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700283 out->Print("\n\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700284 out->Print(
285 "def beta_create_$Service$_server(servicer, pool=None, "
286 "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
287 "Service", service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000288 {
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 =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700318 input_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000319 name_and_input_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700320 input_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000321 name_and_input_module_class_pair++) {
322 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700323 out->Print(
324 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
325 "$InputTypeModuleAndClass$.FromString,\n",
326 "PackageQualifiedServiceName", package_qualified_service_name,
327 "MethodName", name_and_input_module_class_pair->first,
328 "InputTypeModuleAndClass", 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 =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700333 output_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000334 name_and_output_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700335 output_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000336 name_and_output_module_class_pair++) {
337 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700338 out->Print(
339 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
340 "$OutputTypeModuleAndClass$.SerializeToString,\n",
341 "PackageQualifiedServiceName", package_qualified_service_name,
342 "MethodName", name_and_output_module_class_pair->first,
343 "OutputTypeModuleAndClass",
344 name_and_output_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000345 }
346 out->Print("}\n");
347 out->Print("method_implementations = {\n");
348 for (auto name_and_implementation_constructor =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700349 method_implementation_constructors.begin();
350 name_and_implementation_constructor !=
351 method_implementation_constructors.end();
352 name_and_implementation_constructor++) {
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000353 IndentScope raii_descriptions_indent(out);
354 const grpc::string method_name =
355 name_and_implementation_constructor->first;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700356 out->Print(
357 "(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
358 "face_utilities.$Constructor$(servicer.$Method$),\n",
359 "PackageQualifiedServiceName", package_qualified_service_name,
360 "Method", name_and_implementation_constructor->first, "Constructor",
361 name_and_implementation_constructor->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000362 }
363 out->Print("}\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700364 out->Print(
365 "server_options = beta_implementations.server_options("
366 "request_deserializers=request_deserializers, "
367 "response_serializers=response_serializers, "
368 "thread_pool=pool, thread_pool_size=pool_size, "
369 "default_timeout=default_timeout, "
370 "maximum_timeout=maximum_timeout)\n");
371 out->Print(
372 "return beta_implementations.server(method_implementations, "
373 "options=server_options)\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000374 }
375 return true;
376}
377
378bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
379 const ServiceDescriptor* service, Printer* out) {
380 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemiac592452016-07-01 11:58:04 -0700381 "Service", service->name(),
382 });
Ken Paysonbe187b02016-05-06 15:32:58 -0700383 out->Print("\n\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700384 out->Print(dict,
385 "def beta_create_$Service$_stub(channel, host=None,"
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000386 " metadata_transformer=None, pool=None, pool_size=None):\n");
387 {
388 IndentScope raii_create_server_indent(out);
389 map<grpc::string, grpc::string> method_cardinalities;
Ken Paysonbe187b02016-05-06 15:32:58 -0700390 map<grpc::string, grpc::string> input_message_modules_and_classes;
391 map<grpc::string, grpc::string> output_message_modules_and_classes;
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000392 for (int i = 0; i < service->method_count(); ++i) {
393 const MethodDescriptor* method = service->method(i);
394 const grpc::string method_cardinality =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700395 grpc::string(method->client_streaming() ? "STREAM" : "UNARY") + "_" +
Ken Paysonbe187b02016-05-06 15:32:58 -0700396 grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
397 grpc::string input_message_module_and_class;
398 if (!GetModuleAndMessagePath(method->input_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000399 &input_message_module_and_class)) {
400 return false;
401 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700402 grpc::string output_message_module_and_class;
403 if (!GetModuleAndMessagePath(method->output_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000404 &output_message_module_and_class)) {
405 return false;
406 }
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000407 method_cardinalities.insert(
408 make_pair(method->name(), method_cardinality));
409 input_message_modules_and_classes.insert(
410 make_pair(method->name(), input_message_module_and_class));
411 output_message_modules_and_classes.insert(
412 make_pair(method->name(), output_message_module_and_class));
413 }
414 out->Print("request_serializers = {\n");
415 for (auto name_and_input_module_class_pair =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700416 input_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000417 name_and_input_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700418 input_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000419 name_and_input_module_class_pair++) {
420 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700421 out->Print(
422 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
423 "$InputTypeModuleAndClass$.SerializeToString,\n",
424 "PackageQualifiedServiceName", package_qualified_service_name,
425 "MethodName", name_and_input_module_class_pair->first,
426 "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000427 }
428 out->Print("}\n");
429 out->Print("response_deserializers = {\n");
430 for (auto name_and_output_module_class_pair =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700431 output_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000432 name_and_output_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700433 output_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000434 name_and_output_module_class_pair++) {
435 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700436 out->Print(
437 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
438 "$OutputTypeModuleAndClass$.FromString,\n",
439 "PackageQualifiedServiceName", package_qualified_service_name,
440 "MethodName", name_and_output_module_class_pair->first,
441 "OutputTypeModuleAndClass",
442 name_and_output_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000443 }
444 out->Print("}\n");
445 out->Print("cardinalities = {\n");
446 for (auto name_and_cardinality = method_cardinalities.begin();
447 name_and_cardinality != method_cardinalities.end();
448 name_and_cardinality++) {
449 IndentScope raii_descriptions_indent(out);
450 out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700451 "Method", name_and_cardinality->first, "Cardinality",
452 name_and_cardinality->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000453 }
454 out->Print("}\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000455 out->Print(
Masood Malekghassemiac592452016-07-01 11:58:04 -0700456 "stub_options = beta_implementations.stub_options("
457 "host=host, metadata_transformer=metadata_transformer, "
458 "request_serializers=request_serializers, "
459 "response_deserializers=response_deserializers, "
460 "thread_pool=pool, thread_pool_size=pool_size)\n");
461 out->Print(
462 "return beta_implementations.dynamic_stub(channel, "
463 "\'$PackageQualifiedServiceName$\', "
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000464 "cardinalities, options=stub_options)\n",
465 "PackageQualifiedServiceName", package_qualified_service_name);
466 }
467 return true;
468}
469
Nathaniel Manista45479402016-06-13 20:14:18 +0000470bool PrintStub(const grpc::string& package_qualified_service_name,
471 const ServiceDescriptor* service, Printer* out) {
472 out->Print("\n\n");
473 out->Print("class $Service$Stub(object):\n", "Service", service->name());
474 {
475 IndentScope raii_class_indent(out);
476 PrintAllComments(service, out);
477 out->Print("\n");
478 out->Print("def __init__(self, channel):\n");
479 {
480 IndentScope raii_init_indent(out);
481 out->Print("\"\"\"Constructor.\n");
482 out->Print("\n");
483 out->Print("Args:\n");
484 {
485 IndentScope raii_args_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700486 out->Print("channel: A grpc.Channel.\n");
Nathaniel Manista45479402016-06-13 20:14:18 +0000487 }
488 out->Print("\"\"\"\n");
489 for (int i = 0; i < service->method_count(); ++i) {
490 auto method = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700491 auto multi_callable_constructor =
492 grpc::string(method->client_streaming() ? "stream" : "unary") +
493 "_" + grpc::string(method->server_streaming() ? "stream" : "unary");
494 grpc::string request_module_and_class;
495 if (!GetModuleAndMessagePath(method->input_type(), service,
496 &request_module_and_class)) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000497 return false;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700498 }
499 grpc::string response_module_and_class;
500 if (!GetModuleAndMessagePath(method->output_type(), service,
501 &response_module_and_class)) {
502 return false;
503 }
504 out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
505 "Method", method->name(), "MultiCallableConstructor",
506 multi_callable_constructor);
507 {
Nathaniel Manista45479402016-06-13 20:14:18 +0000508 IndentScope raii_first_attribute_indent(out);
509 IndentScope raii_second_attribute_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700510 out->Print("'/$PackageQualifiedService$/$Method$',\n",
511 "PackageQualifiedService", package_qualified_service_name,
512 "Method", method->name());
513 out->Print(
514 "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
515 "RequestModuleAndClass", request_module_and_class);
516 out->Print(
Nathaniel Manista45479402016-06-13 20:14:18 +0000517 "response_deserializer=$ResponseModuleAndClass$.FromString,\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700518 "ResponseModuleAndClass", response_module_and_class);
519 out->Print(")\n");
520 }
Nathaniel Manista45479402016-06-13 20:14:18 +0000521 }
522 }
523 }
524 return true;
525}
526
527bool PrintServicer(const ServiceDescriptor* service, Printer* out) {
528 out->Print("\n\n");
529 out->Print("class $Service$Servicer(object):\n", "Service", service->name());
530 {
531 IndentScope raii_class_indent(out);
532 PrintAllComments(service, out);
533 for (int i = 0; i < service->method_count(); ++i) {
534 auto method = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700535 grpc::string arg_name =
536 method->client_streaming() ? "request_iterator" : "request";
Nathaniel Manista45479402016-06-13 20:14:18 +0000537 out->Print("\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700538 out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
539 method->name(), "ArgName", arg_name);
Nathaniel Manista45479402016-06-13 20:14:18 +0000540 {
541 IndentScope raii_method_indent(out);
542 PrintAllComments(method, out);
543 out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n");
544 out->Print("context.set_details('Method not implemented!')\n");
545 out->Print("raise NotImplementedError('Method not implemented!')\n");
546 }
547 }
548 }
549 return true;
550}
551
Masood Malekghassemiac592452016-07-01 11:58:04 -0700552bool PrintAddServicerToServer(
553 const grpc::string& package_qualified_service_name,
554 const ServiceDescriptor* service, Printer* out) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000555 out->Print("\n\n");
556 out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700557 "Service", service->name());
Nathaniel Manista45479402016-06-13 20:14:18 +0000558 {
559 IndentScope raii_class_indent(out);
560 out->Print("rpc_method_handlers = {\n");
561 {
562 IndentScope raii_dict_first_indent(out);
563 IndentScope raii_dict_second_indent(out);
564 for (int i = 0; i < service->method_count(); ++i) {
565 auto method = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700566 auto method_handler_constructor =
Nathaniel Manista45479402016-06-13 20:14:18 +0000567 grpc::string(method->client_streaming() ? "stream" : "unary") +
Masood Malekghassemiac592452016-07-01 11:58:04 -0700568 "_" +
Nathaniel Manista45479402016-06-13 20:14:18 +0000569 grpc::string(method->server_streaming() ? "stream" : "unary") +
570 "_rpc_method_handler";
Masood Malekghassemiac592452016-07-01 11:58:04 -0700571 grpc::string request_module_and_class;
572 if (!GetModuleAndMessagePath(method->input_type(), service,
573 &request_module_and_class)) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000574 return false;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700575 }
576 grpc::string response_module_and_class;
577 if (!GetModuleAndMessagePath(method->output_type(), service,
578 &response_module_and_class)) {
579 return false;
580 }
581 out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n", "Method",
582 method->name(), "MethodHandlerConstructor",
583 method_handler_constructor);
584 {
Nathaniel Manista45479402016-06-13 20:14:18 +0000585 IndentScope raii_call_first_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700586 IndentScope raii_call_second_indent(out);
587 out->Print("servicer.$Method$,\n", "Method", method->name());
588 out->Print(
589 "request_deserializer=$RequestModuleAndClass$.FromString,\n",
590 "RequestModuleAndClass", request_module_and_class);
591 out->Print(
592 "response_serializer=$ResponseModuleAndClass$.SerializeToString,"
593 "\n",
594 "ResponseModuleAndClass", response_module_and_class);
595 }
596 out->Print("),\n");
Nathaniel Manista45479402016-06-13 20:14:18 +0000597 }
598 }
599 out->Print("}\n");
600 out->Print("generic_handler = grpc.method_handlers_generic_handler(\n");
601 {
602 IndentScope raii_call_first_indent(out);
603 IndentScope raii_call_second_indent(out);
604 out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700605 "PackageQualifiedServiceName", package_qualified_service_name);
Nathaniel Manista45479402016-06-13 20:14:18 +0000606 }
607 out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
608 }
609 return true;
610}
611
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700612bool PrintPreamble(const FileDescriptor* file,
613 const GeneratorConfiguration& config, Printer* out) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000614 out->Print("import $Package$\n", "Package", config.grpc_package_root);
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000615 out->Print("from $Package$ import implementations as beta_implementations\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000616 "Package", config.beta_package_root);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700617 out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package",
618 config.beta_package_root);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000619 out->Print("from grpc.framework.common import cardinality\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700620 out->Print(
621 "from grpc.framework.interfaces.face import utilities as "
622 "face_utilities\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800623 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800624}
625
626} // namespace
627
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700628pair<bool, grpc::string> GetServices(const FileDescriptor* file,
Nathaniel Manistadc8c3232016-01-16 18:28:45 +0000629 const GeneratorConfiguration& config) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700630 grpc::string output;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800631 {
632 // Scope the output stream so it closes and finalizes output to the string.
633 StringOutputStream output_stream(&output);
634 Printer out(&output_stream, '$');
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700635 if (!PrintPreamble(file, config, &out)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800636 return make_pair(false, "");
637 }
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000638 auto package = file->package();
639 if (!package.empty()) {
640 package = package.append(".");
641 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800642 for (int i = 0; i < file->service_count(); ++i) {
643 auto service = file->service(i);
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000644 auto package_qualified_service_name = package + service->name();
Nathaniel Manista45479402016-06-13 20:14:18 +0000645 if (!(PrintStub(package_qualified_service_name, service, &out) &&
Masood Malekghassemiac592452016-07-01 11:58:04 -0700646 PrintServicer(service, &out) &&
647 PrintAddServicerToServer(package_qualified_service_name, service,
648 &out) &&
649 PrintBetaServicer(service, &out) && PrintBetaStub(service, &out) &&
650 PrintBetaServerFactory(package_qualified_service_name, service,
651 &out) &&
652 PrintBetaStubFactory(package_qualified_service_name, service,
653 &out))) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800654 return make_pair(false, "");
655 }
656 }
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800657 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800658 return make_pair(true, std::move(output));
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800659}
660
661} // namespace grpc_python_generator