blob: 6830f49931dc01aad27d7bc8393218328238a404 [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);
Nicolas "Pixel" Noblebeeeddd2016-09-29 20:27:23 +0200237 out->Print(
238 "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n"
239 "\nIt is recommended to use the GA API (classes and functions in this\n"
240 "file not marked beta) for all further purposes. This class was "
241 "generated\n"
242 "only to ease transition from grpcio<0.15.0 to "
243 "grpcio>=0.15.0.\"\"\"\n");
yang-gb0de7162016-05-03 15:48:19 -0700244 PrintAllComments(service, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000245 for (int i = 0; i < service->method_count(); ++i) {
246 auto meth = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700247 grpc::string arg_name =
248 meth->client_streaming() ? "request_iterator" : "request";
249 out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
250 meth->name(), "ArgName", arg_name);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000251 {
252 IndentScope raii_method_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700253 PrintAllComments(meth, out);
Masood Malekghassemi832ae812016-04-27 18:38:54 -0700254 out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000255 }
256 }
257 }
258 return true;
259}
260
Masood Malekghassemiac592452016-07-01 11:58:04 -0700261bool PrintBetaStub(const ServiceDescriptor* service, Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700262 out->Print("\n\n");
yang-gb0de7162016-05-03 15:48:19 -0700263 out->Print("class Beta$Service$Stub(object):\n", "Service", service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000264 {
265 IndentScope raii_class_indent(out);
Nicolas "Pixel" Noblebeeeddd2016-09-29 20:27:23 +0200266 out->Print(
267 "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n"
268 "\nIt is recommended to use the GA API (classes and functions in this\n"
269 "file not marked beta) for all further purposes. This class was "
270 "generated\n"
271 "only to ease transition from grpcio<0.15.0 to "
272 "grpcio>=0.15.0.\"\"\"\n");
yang-gb0de7162016-05-03 15:48:19 -0700273 PrintAllComments(service, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000274 for (int i = 0; i < service->method_count(); ++i) {
275 const MethodDescriptor* meth = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700276 grpc::string arg_name =
277 meth->client_streaming() ? "request_iterator" : "request";
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000278 auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
Masood Malekghassemiac592452016-07-01 11:58:04 -0700279 out->Print(methdict,
280 "def $Method$(self, $ArgName$, timeout, metadata=None, "
281 "with_call=False, protocol_options=None):\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000282 {
283 IndentScope raii_method_indent(out);
yang-gb0de7162016-05-03 15:48:19 -0700284 PrintAllComments(meth, out);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000285 out->Print("raise NotImplementedError()\n");
286 }
287 if (!meth->server_streaming()) {
288 out->Print(methdict, "$Method$.future = None\n");
289 }
290 }
291 }
292 return true;
293}
294
295bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
296 const ServiceDescriptor* service, Printer* out) {
Ken Paysonbe187b02016-05-06 15:32:58 -0700297 out->Print("\n\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700298 out->Print(
299 "def beta_create_$Service$_server(servicer, pool=None, "
300 "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
301 "Service", service->name());
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000302 {
303 IndentScope raii_create_server_indent(out);
Nicolas "Pixel" Noblebeeeddd2016-09-29 20:27:23 +0200304 out->Print(
305 "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n"
306 "\nIt is recommended to use the GA API (classes and functions in this\n"
307 "file not marked beta) for all further purposes. This function was\n"
308 "generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"
309 "\"\"\"\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000310 map<grpc::string, grpc::string> method_implementation_constructors;
Ken Paysonbe187b02016-05-06 15:32:58 -0700311 map<grpc::string, grpc::string> input_message_modules_and_classes;
312 map<grpc::string, grpc::string> output_message_modules_and_classes;
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000313 for (int i = 0; i < service->method_count(); ++i) {
314 const MethodDescriptor* method = service->method(i);
315 const grpc::string method_implementation_constructor =
316 grpc::string(method->client_streaming() ? "stream_" : "unary_") +
317 grpc::string(method->server_streaming() ? "stream_" : "unary_") +
318 "inline";
Ken Paysonbe187b02016-05-06 15:32:58 -0700319 grpc::string input_message_module_and_class;
320 if (!GetModuleAndMessagePath(method->input_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000321 &input_message_module_and_class)) {
322 return false;
323 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700324 grpc::string output_message_module_and_class;
325 if (!GetModuleAndMessagePath(method->output_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000326 &output_message_module_and_class)) {
327 return false;
328 }
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000329 method_implementation_constructors.insert(
330 make_pair(method->name(), method_implementation_constructor));
331 input_message_modules_and_classes.insert(
332 make_pair(method->name(), input_message_module_and_class));
333 output_message_modules_and_classes.insert(
334 make_pair(method->name(), output_message_module_and_class));
335 }
336 out->Print("request_deserializers = {\n");
337 for (auto name_and_input_module_class_pair =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700338 input_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000339 name_and_input_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700340 input_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000341 name_and_input_module_class_pair++) {
342 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700343 out->Print(
344 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
345 "$InputTypeModuleAndClass$.FromString,\n",
346 "PackageQualifiedServiceName", package_qualified_service_name,
347 "MethodName", name_and_input_module_class_pair->first,
348 "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000349 }
350 out->Print("}\n");
351 out->Print("response_serializers = {\n");
352 for (auto name_and_output_module_class_pair =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700353 output_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000354 name_and_output_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700355 output_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000356 name_and_output_module_class_pair++) {
357 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700358 out->Print(
359 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
360 "$OutputTypeModuleAndClass$.SerializeToString,\n",
361 "PackageQualifiedServiceName", package_qualified_service_name,
362 "MethodName", name_and_output_module_class_pair->first,
363 "OutputTypeModuleAndClass",
364 name_and_output_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000365 }
366 out->Print("}\n");
367 out->Print("method_implementations = {\n");
368 for (auto name_and_implementation_constructor =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700369 method_implementation_constructors.begin();
370 name_and_implementation_constructor !=
371 method_implementation_constructors.end();
372 name_and_implementation_constructor++) {
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000373 IndentScope raii_descriptions_indent(out);
374 const grpc::string method_name =
375 name_and_implementation_constructor->first;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700376 out->Print(
377 "(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
378 "face_utilities.$Constructor$(servicer.$Method$),\n",
379 "PackageQualifiedServiceName", package_qualified_service_name,
380 "Method", name_and_implementation_constructor->first, "Constructor",
381 name_and_implementation_constructor->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000382 }
383 out->Print("}\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700384 out->Print(
385 "server_options = beta_implementations.server_options("
386 "request_deserializers=request_deserializers, "
387 "response_serializers=response_serializers, "
388 "thread_pool=pool, thread_pool_size=pool_size, "
389 "default_timeout=default_timeout, "
390 "maximum_timeout=maximum_timeout)\n");
391 out->Print(
392 "return beta_implementations.server(method_implementations, "
393 "options=server_options)\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000394 }
395 return true;
396}
397
398bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
399 const ServiceDescriptor* service, Printer* out) {
400 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemiac592452016-07-01 11:58:04 -0700401 "Service", service->name(),
402 });
Ken Paysonbe187b02016-05-06 15:32:58 -0700403 out->Print("\n\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700404 out->Print(dict,
405 "def beta_create_$Service$_stub(channel, host=None,"
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000406 " metadata_transformer=None, pool=None, pool_size=None):\n");
407 {
408 IndentScope raii_create_server_indent(out);
Nicolas "Pixel" Noblebeeeddd2016-09-29 20:27:23 +0200409 out->Print(
410 "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n"
411 "\nIt is recommended to use the GA API (classes and functions in this\n"
412 "file not marked beta) for all further purposes. This function was\n"
413 "generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"
414 "\"\"\"\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000415 map<grpc::string, grpc::string> method_cardinalities;
Ken Paysonbe187b02016-05-06 15:32:58 -0700416 map<grpc::string, grpc::string> input_message_modules_and_classes;
417 map<grpc::string, grpc::string> output_message_modules_and_classes;
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000418 for (int i = 0; i < service->method_count(); ++i) {
419 const MethodDescriptor* method = service->method(i);
420 const grpc::string method_cardinality =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700421 grpc::string(method->client_streaming() ? "STREAM" : "UNARY") + "_" +
Ken Paysonbe187b02016-05-06 15:32:58 -0700422 grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
423 grpc::string input_message_module_and_class;
424 if (!GetModuleAndMessagePath(method->input_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000425 &input_message_module_and_class)) {
426 return false;
427 }
Ken Paysonbe187b02016-05-06 15:32:58 -0700428 grpc::string output_message_module_and_class;
429 if (!GetModuleAndMessagePath(method->output_type(), service,
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000430 &output_message_module_and_class)) {
431 return false;
432 }
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000433 method_cardinalities.insert(
434 make_pair(method->name(), method_cardinality));
435 input_message_modules_and_classes.insert(
436 make_pair(method->name(), input_message_module_and_class));
437 output_message_modules_and_classes.insert(
438 make_pair(method->name(), output_message_module_and_class));
439 }
440 out->Print("request_serializers = {\n");
441 for (auto name_and_input_module_class_pair =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700442 input_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000443 name_and_input_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700444 input_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000445 name_and_input_module_class_pair++) {
446 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700447 out->Print(
448 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
449 "$InputTypeModuleAndClass$.SerializeToString,\n",
450 "PackageQualifiedServiceName", package_qualified_service_name,
451 "MethodName", name_and_input_module_class_pair->first,
452 "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000453 }
454 out->Print("}\n");
455 out->Print("response_deserializers = {\n");
456 for (auto name_and_output_module_class_pair =
Masood Malekghassemiac592452016-07-01 11:58:04 -0700457 output_message_modules_and_classes.begin();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000458 name_and_output_module_class_pair !=
Masood Malekghassemiac592452016-07-01 11:58:04 -0700459 output_message_modules_and_classes.end();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000460 name_and_output_module_class_pair++) {
461 IndentScope raii_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700462 out->Print(
463 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
464 "$OutputTypeModuleAndClass$.FromString,\n",
465 "PackageQualifiedServiceName", package_qualified_service_name,
466 "MethodName", name_and_output_module_class_pair->first,
467 "OutputTypeModuleAndClass",
468 name_and_output_module_class_pair->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000469 }
470 out->Print("}\n");
471 out->Print("cardinalities = {\n");
472 for (auto name_and_cardinality = method_cardinalities.begin();
473 name_and_cardinality != method_cardinalities.end();
474 name_and_cardinality++) {
475 IndentScope raii_descriptions_indent(out);
476 out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700477 "Method", name_and_cardinality->first, "Cardinality",
478 name_and_cardinality->second);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000479 }
480 out->Print("}\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000481 out->Print(
Masood Malekghassemiac592452016-07-01 11:58:04 -0700482 "stub_options = beta_implementations.stub_options("
483 "host=host, metadata_transformer=metadata_transformer, "
484 "request_serializers=request_serializers, "
485 "response_deserializers=response_deserializers, "
486 "thread_pool=pool, thread_pool_size=pool_size)\n");
487 out->Print(
488 "return beta_implementations.dynamic_stub(channel, "
489 "\'$PackageQualifiedServiceName$\', "
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000490 "cardinalities, options=stub_options)\n",
491 "PackageQualifiedServiceName", package_qualified_service_name);
492 }
493 return true;
494}
495
Nathaniel Manista45479402016-06-13 20:14:18 +0000496bool PrintStub(const grpc::string& package_qualified_service_name,
497 const ServiceDescriptor* service, Printer* out) {
498 out->Print("\n\n");
499 out->Print("class $Service$Stub(object):\n", "Service", service->name());
500 {
501 IndentScope raii_class_indent(out);
502 PrintAllComments(service, out);
503 out->Print("\n");
504 out->Print("def __init__(self, channel):\n");
505 {
506 IndentScope raii_init_indent(out);
507 out->Print("\"\"\"Constructor.\n");
508 out->Print("\n");
509 out->Print("Args:\n");
510 {
511 IndentScope raii_args_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700512 out->Print("channel: A grpc.Channel.\n");
Nathaniel Manista45479402016-06-13 20:14:18 +0000513 }
514 out->Print("\"\"\"\n");
515 for (int i = 0; i < service->method_count(); ++i) {
516 auto method = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700517 auto multi_callable_constructor =
518 grpc::string(method->client_streaming() ? "stream" : "unary") +
519 "_" + grpc::string(method->server_streaming() ? "stream" : "unary");
520 grpc::string request_module_and_class;
521 if (!GetModuleAndMessagePath(method->input_type(), service,
522 &request_module_and_class)) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000523 return false;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700524 }
525 grpc::string response_module_and_class;
526 if (!GetModuleAndMessagePath(method->output_type(), service,
527 &response_module_and_class)) {
528 return false;
529 }
530 out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
531 "Method", method->name(), "MultiCallableConstructor",
532 multi_callable_constructor);
533 {
Nathaniel Manista45479402016-06-13 20:14:18 +0000534 IndentScope raii_first_attribute_indent(out);
535 IndentScope raii_second_attribute_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700536 out->Print("'/$PackageQualifiedService$/$Method$',\n",
537 "PackageQualifiedService", package_qualified_service_name,
538 "Method", method->name());
539 out->Print(
540 "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
541 "RequestModuleAndClass", request_module_and_class);
542 out->Print(
Nathaniel Manista45479402016-06-13 20:14:18 +0000543 "response_deserializer=$ResponseModuleAndClass$.FromString,\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700544 "ResponseModuleAndClass", response_module_and_class);
545 out->Print(")\n");
546 }
Nathaniel Manista45479402016-06-13 20:14:18 +0000547 }
548 }
549 }
550 return true;
551}
552
553bool PrintServicer(const ServiceDescriptor* service, Printer* out) {
554 out->Print("\n\n");
555 out->Print("class $Service$Servicer(object):\n", "Service", service->name());
556 {
557 IndentScope raii_class_indent(out);
558 PrintAllComments(service, out);
559 for (int i = 0; i < service->method_count(); ++i) {
560 auto method = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700561 grpc::string arg_name =
562 method->client_streaming() ? "request_iterator" : "request";
Nathaniel Manista45479402016-06-13 20:14:18 +0000563 out->Print("\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700564 out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
565 method->name(), "ArgName", arg_name);
Nathaniel Manista45479402016-06-13 20:14:18 +0000566 {
567 IndentScope raii_method_indent(out);
568 PrintAllComments(method, out);
569 out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n");
570 out->Print("context.set_details('Method not implemented!')\n");
571 out->Print("raise NotImplementedError('Method not implemented!')\n");
572 }
573 }
574 }
575 return true;
576}
577
Masood Malekghassemiac592452016-07-01 11:58:04 -0700578bool PrintAddServicerToServer(
579 const grpc::string& package_qualified_service_name,
580 const ServiceDescriptor* service, Printer* out) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000581 out->Print("\n\n");
582 out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700583 "Service", service->name());
Nathaniel Manista45479402016-06-13 20:14:18 +0000584 {
585 IndentScope raii_class_indent(out);
586 out->Print("rpc_method_handlers = {\n");
587 {
588 IndentScope raii_dict_first_indent(out);
589 IndentScope raii_dict_second_indent(out);
590 for (int i = 0; i < service->method_count(); ++i) {
591 auto method = service->method(i);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700592 auto method_handler_constructor =
Nathaniel Manista45479402016-06-13 20:14:18 +0000593 grpc::string(method->client_streaming() ? "stream" : "unary") +
Masood Malekghassemiac592452016-07-01 11:58:04 -0700594 "_" +
Nathaniel Manista45479402016-06-13 20:14:18 +0000595 grpc::string(method->server_streaming() ? "stream" : "unary") +
596 "_rpc_method_handler";
Masood Malekghassemiac592452016-07-01 11:58:04 -0700597 grpc::string request_module_and_class;
598 if (!GetModuleAndMessagePath(method->input_type(), service,
599 &request_module_and_class)) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000600 return false;
Masood Malekghassemiac592452016-07-01 11:58:04 -0700601 }
602 grpc::string response_module_and_class;
603 if (!GetModuleAndMessagePath(method->output_type(), service,
604 &response_module_and_class)) {
605 return false;
606 }
607 out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n", "Method",
608 method->name(), "MethodHandlerConstructor",
609 method_handler_constructor);
610 {
Nathaniel Manista45479402016-06-13 20:14:18 +0000611 IndentScope raii_call_first_indent(out);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700612 IndentScope raii_call_second_indent(out);
613 out->Print("servicer.$Method$,\n", "Method", method->name());
614 out->Print(
615 "request_deserializer=$RequestModuleAndClass$.FromString,\n",
616 "RequestModuleAndClass", request_module_and_class);
617 out->Print(
618 "response_serializer=$ResponseModuleAndClass$.SerializeToString,"
619 "\n",
620 "ResponseModuleAndClass", response_module_and_class);
621 }
622 out->Print("),\n");
Nathaniel Manista45479402016-06-13 20:14:18 +0000623 }
624 }
625 out->Print("}\n");
626 out->Print("generic_handler = grpc.method_handlers_generic_handler(\n");
627 {
628 IndentScope raii_call_first_indent(out);
629 IndentScope raii_call_second_indent(out);
630 out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
Masood Malekghassemiac592452016-07-01 11:58:04 -0700631 "PackageQualifiedServiceName", package_qualified_service_name);
Nathaniel Manista45479402016-06-13 20:14:18 +0000632 }
633 out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
634 }
635 return true;
636}
637
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700638bool PrintPreamble(const FileDescriptor* file,
639 const GeneratorConfiguration& config, Printer* out) {
Nathaniel Manista45479402016-06-13 20:14:18 +0000640 out->Print("import $Package$\n", "Package", config.grpc_package_root);
Nathaniel Manistaf65d3c12015-09-05 03:55:19 +0000641 out->Print("from $Package$ import implementations as beta_implementations\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000642 "Package", config.beta_package_root);
Masood Malekghassemiac592452016-07-01 11:58:04 -0700643 out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package",
644 config.beta_package_root);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000645 out->Print("from grpc.framework.common import cardinality\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700646 out->Print(
647 "from grpc.framework.interfaces.face import utilities as "
648 "face_utilities\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800649 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800650}
651
652} // namespace
653
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700654pair<bool, grpc::string> GetServices(const FileDescriptor* file,
Nathaniel Manistadc8c3232016-01-16 18:28:45 +0000655 const GeneratorConfiguration& config) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700656 grpc::string output;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800657 {
658 // Scope the output stream so it closes and finalizes output to the string.
659 StringOutputStream output_stream(&output);
660 Printer out(&output_stream, '$');
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700661 if (!PrintPreamble(file, config, &out)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800662 return make_pair(false, "");
663 }
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000664 auto package = file->package();
665 if (!package.empty()) {
666 package = package.append(".");
667 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800668 for (int i = 0; i < file->service_count(); ++i) {
669 auto service = file->service(i);
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000670 auto package_qualified_service_name = package + service->name();
Nathaniel Manista45479402016-06-13 20:14:18 +0000671 if (!(PrintStub(package_qualified_service_name, service, &out) &&
Masood Malekghassemiac592452016-07-01 11:58:04 -0700672 PrintServicer(service, &out) &&
673 PrintAddServicerToServer(package_qualified_service_name, service,
674 &out) &&
675 PrintBetaServicer(service, &out) && PrintBetaStub(service, &out) &&
676 PrintBetaServerFactory(package_qualified_service_name, service,
677 &out) &&
678 PrintBetaStubFactory(package_qualified_service_name, service,
679 &out))) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800680 return make_pair(false, "");
681 }
682 }
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800683 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800684 return make_pair(true, std::move(output));
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800685}
686
687} // namespace grpc_python_generator