blob: c2d4cda31a78d746f2ad51040484a032fec0e9ae [file] [log] [blame]
Masood Malekghassemif8e297a2015-02-19 15:39:32 -08001/*
2 *
3 * Copyright 2015, Google Inc.
4 * 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 "grpc++/config.h"
46#include "src/compiler/config.h"
Nicolas "Pixel" Noble93fa0982015-02-27 21:50:58 +010047#include "src/compiler/generator_helpers.h"
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080048#include "src/compiler/python_generator.h"
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080049
Nicolas "Pixel" Noble93fa0982015-02-27 21:50:58 +010050using grpc_generator::StringReplace;
51using grpc_generator::StripProto;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070052using grpc::protobuf::Descriptor;
53using grpc::protobuf::FileDescriptor;
54using grpc::protobuf::MethodDescriptor;
55using grpc::protobuf::ServiceDescriptor;
56using grpc::protobuf::compiler::GeneratorContext;
57using grpc::protobuf::io::CodedOutputStream;
58using grpc::protobuf::io::Printer;
59using grpc::protobuf::io::StringOutputStream;
60using grpc::protobuf::io::ZeroCopyOutputStream;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080061using std::initializer_list;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080062using std::make_pair;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080063using std::map;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080064using std::pair;
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -080065using std::replace;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -080066using std::vector;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -080067
68namespace grpc_python_generator {
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070069
70PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
71 : config_(config) {}
72
73PythonGrpcGenerator::~PythonGrpcGenerator() {}
74
75bool PythonGrpcGenerator::Generate(
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070076 const FileDescriptor* file, const grpc::string& parameter,
77 GeneratorContext* context, grpc::string* error) const {
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070078 // Get output file name.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070079 grpc::string file_name;
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070080 static const int proto_suffix_length = strlen(".proto");
81 if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
82 file->name().find_last_of(".proto") == file->name().size() - 1) {
83 file_name = file->name().substr(
84 0, file->name().size() - proto_suffix_length) + "_pb2.py";
85 } else {
86 *error = "Invalid proto file name. Proto file must end with .proto";
87 return false;
88 }
89
90 std::unique_ptr<ZeroCopyOutputStream> output(
91 context->OpenForInsert(file_name, "module_scope"));
92 CodedOutputStream coded_out(output.get());
93 bool success = false;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070094 grpc::string code = "";
Masood Malekghassemi3bb52152015-03-17 21:52:52 -070095 tie(success, code) = grpc_python_generator::GetServices(file, config_);
96 if (success) {
97 coded_out.WriteRaw(code.data(), code.size());
98 return true;
99 } else {
100 return false;
101 }
102}
103
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800104namespace {
105//////////////////////////////////
106// BEGIN FORMATTING BOILERPLATE //
107//////////////////////////////////
108
109// Converts an initializer list of the form { key0, value0, key1, value1, ... }
110// into a map of key* to value*. Is merely a readability helper for later code.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700111map<grpc::string, grpc::string> ListToDict(
112 const initializer_list<grpc::string>& values) {
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800113 assert(values.size() % 2 == 0);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700114 map<grpc::string, grpc::string> value_map;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800115 auto value_iter = values.begin();
116 for (unsigned i = 0; i < values.size()/2; ++i) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700117 grpc::string key = *value_iter;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800118 ++value_iter;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700119 grpc::string value = *value_iter;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800120 value_map[key] = value;
121 ++value_iter;
122 }
123 return value_map;
124}
125
126// Provides RAII indentation handling. Use as:
127// {
128// IndentScope raii_my_indent_var_name_here(my_py_printer);
129// // constructor indented my_py_printer
130// ...
131// // destructor called at end of scope, un-indenting my_py_printer
132// }
133class IndentScope {
134 public:
135 explicit IndentScope(Printer* printer) : printer_(printer) {
136 printer_->Indent();
137 }
138
139 ~IndentScope() {
140 printer_->Outdent();
141 }
142
143 private:
144 Printer* printer_;
145};
146
147////////////////////////////////
148// END FORMATTING BOILERPLATE //
149////////////////////////////////
150
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800151bool PrintServicer(const ServiceDescriptor* service,
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800152 Printer* out) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700153 grpc::string doc = "<fill me in later!>";
154 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800155 "Service", service->name(),
156 "Documentation", doc,
157 });
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800158 out->Print(dict, "class EarlyAdopter$Service$Servicer(object):\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800159 {
160 IndentScope raii_class_indent(out);
161 out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800162 out->Print("__metaclass__ = abc.ABCMeta\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800163 for (int i = 0; i < service->method_count(); ++i) {
164 auto meth = service->method(i);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700165 grpc::string arg_name = meth->client_streaming() ?
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800166 "request_iterator" : "request";
167 out->Print("@abc.abstractmethod\n");
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -0800168 out->Print("def $Method$(self, $ArgName$, context):\n",
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800169 "Method", meth->name(), "ArgName", arg_name);
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800170 {
171 IndentScope raii_method_indent(out);
172 out->Print("raise NotImplementedError()\n");
173 }
174 }
175 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800176 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800177}
178
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800179bool PrintServer(const ServiceDescriptor* service, Printer* out) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700180 grpc::string doc = "<fill me in later!>";
181 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800182 "Service", service->name(),
183 "Documentation", doc,
184 });
185 out->Print(dict, "class EarlyAdopter$Service$Server(object):\n");
186 {
187 IndentScope raii_class_indent(out);
188 out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
189 out->Print("__metaclass__ = abc.ABCMeta\n");
190 out->Print("@abc.abstractmethod\n");
191 out->Print("def start(self):\n");
192 {
193 IndentScope raii_method_indent(out);
194 out->Print("raise NotImplementedError()\n");
195 }
196
197 out->Print("@abc.abstractmethod\n");
198 out->Print("def stop(self):\n");
199 {
200 IndentScope raii_method_indent(out);
201 out->Print("raise NotImplementedError()\n");
202 }
203 }
204 return true;
205}
206
207bool PrintStub(const ServiceDescriptor* service,
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800208 Printer* out) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700209 grpc::string doc = "<fill me in later!>";
210 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800211 "Service", service->name(),
212 "Documentation", doc,
213 });
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800214 out->Print(dict, "class EarlyAdopter$Service$Stub(object):\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800215 {
216 IndentScope raii_class_indent(out);
217 out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800218 out->Print("__metaclass__ = abc.ABCMeta\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800219 for (int i = 0; i < service->method_count(); ++i) {
220 const MethodDescriptor* meth = service->method(i);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700221 grpc::string arg_name = meth->client_streaming() ?
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800222 "request_iterator" : "request";
223 auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
224 out->Print("@abc.abstractmethod\n");
225 out->Print(methdict, "def $Method$(self, $ArgName$):\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800226 {
227 IndentScope raii_method_indent(out);
228 out->Print("raise NotImplementedError()\n");
229 }
230 out->Print(methdict, "$Method$.async = None\n");
231 }
232 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800233 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800234}
235
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -0800236// TODO(protobuf team): Export `ModuleName` from protobuf's
237// `src/google/protobuf/compiler/python/python_generator.cc` file.
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700238grpc::string ModuleName(const grpc::string& filename) {
239 grpc::string basename = StripProto(filename);
Nicolas "Pixel" Noble93fa0982015-02-27 21:50:58 +0100240 basename = StringReplace(basename, "-", "_");
241 basename = StringReplace(basename, "/", ".");
Masood Malekghassemi40e8cbd2015-02-26 08:39:50 -0800242 return basename + "_pb2";
243}
244
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800245bool GetModuleAndMessagePath(const Descriptor* type,
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700246 pair<grpc::string, grpc::string>* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800247 const Descriptor* path_elem_type = type;
248 vector<const Descriptor*> message_path;
249 do {
250 message_path.push_back(path_elem_type);
251 path_elem_type = path_elem_type->containing_type();
252 } while (path_elem_type != nullptr);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700253 grpc::string file_name = type->file()->name();
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800254 static const int proto_suffix_length = strlen(".proto");
255 if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
256 file_name.find_last_of(".proto") == file_name.size() - 1)) {
257 return false;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800258 }
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700259 grpc::string module = ModuleName(file_name);
260 grpc::string message_type;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800261 for (auto path_iter = message_path.rbegin();
262 path_iter != message_path.rend(); ++path_iter) {
263 message_type += (*path_iter)->name() + ".";
264 }
Craig Tillercf133f42015-02-26 14:05:56 -0800265 // no pop_back prior to C++11
266 message_type.resize(message_type.size() - 1);
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800267 *out = make_pair(module, message_type);
268 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800269}
270
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700271bool PrintServerFactory(const grpc::string& package_qualified_service_name,
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000272 const ServiceDescriptor* service, Printer* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800273 out->Print("def early_adopter_create_$Service$_server(servicer, port, "
274 "root_certificates, key_chain_pairs):\n",
275 "Service", service->name());
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800276 {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800277 IndentScope raii_create_server_indent(out);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700278 map<grpc::string, grpc::string> method_description_constructors;
279 map<grpc::string, pair<grpc::string, grpc::string>>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700280 input_message_modules_and_classes;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700281 map<grpc::string, pair<grpc::string, grpc::string>>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700282 output_message_modules_and_classes;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800283 for (int i = 0; i < service->method_count(); ++i) {
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000284 const MethodDescriptor* method = service->method(i);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700285 const grpc::string method_description_constructor =
286 grpc::string(method->client_streaming() ? "stream_" : "unary_") +
287 grpc::string(method->server_streaming() ? "stream_" : "unary_") +
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000288 "service_description";
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700289 pair<grpc::string, grpc::string> input_message_module_and_class;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000290 if (!GetModuleAndMessagePath(method->input_type(),
291 &input_message_module_and_class)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800292 return false;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800293 }
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700294 pair<grpc::string, grpc::string> output_message_module_and_class;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000295 if (!GetModuleAndMessagePath(method->output_type(),
296 &output_message_module_and_class)) {
297 return false;
298 }
299 // Import the modules that define the messages used in RPCs.
300 out->Print("import $Module$\n", "Module",
301 input_message_module_and_class.first);
302 out->Print("import $Module$\n", "Module",
303 output_message_module_and_class.first);
304 method_description_constructors.insert(
305 make_pair(method->name(), method_description_constructor));
306 input_message_modules_and_classes.insert(
307 make_pair(method->name(), input_message_module_and_class));
308 output_message_modules_and_classes.insert(
309 make_pair(method->name(), output_message_module_and_class));
310 }
311 out->Print("method_service_descriptions = {\n");
312 for (auto& name_and_description_constructor :
313 method_description_constructors) {
314 IndentScope raii_descriptions_indent(out);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700315 const grpc::string method_name = name_and_description_constructor.first;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000316 auto input_message_module_and_class =
317 input_message_modules_and_classes.find(method_name);
318 auto output_message_module_and_class =
319 output_message_modules_and_classes.find(method_name);
320 out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
321 method_name, "Constructor",
322 name_and_description_constructor.second);
323 {
324 IndentScope raii_description_arguments_indent(out);
325 out->Print("servicer.$Method$,\n", "Method", method_name);
326 out->Print(
327 "$InputTypeModule$.$InputTypeClass$.FromString,\n",
328 "InputTypeModule", input_message_module_and_class->second.first,
329 "InputTypeClass", input_message_module_and_class->second.second);
330 out->Print(
331 "$OutputTypeModule$.$OutputTypeClass$.SerializeToString,\n",
332 "OutputTypeModule", output_message_module_and_class->second.first,
333 "OutputTypeClass", output_message_module_and_class->second.second);
334 }
335 out->Print("),\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800336 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800337 out->Print("}\n");
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000338 out->Print(
339 "return implementations.secure_server("
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000340 "\"$PackageQualifiedServiceName$\","
341 " method_service_descriptions, port, root_certificates,"
342 " key_chain_pairs)\n",
343 "PackageQualifiedServiceName", package_qualified_service_name);
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800344 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800345 return true;
346}
347
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700348bool PrintStubFactory(const grpc::string& package_qualified_service_name,
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000349 const ServiceDescriptor* service, Printer* out) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700350 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800351 "Service", service->name(),
352 });
353 out->Print(dict, "def early_adopter_create_$Service$_stub(host, port):\n");
354 {
355 IndentScope raii_create_server_indent(out);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700356 map<grpc::string, grpc::string> method_description_constructors;
357 map<grpc::string, pair<grpc::string, grpc::string>>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700358 input_message_modules_and_classes;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700359 map<grpc::string, pair<grpc::string, grpc::string>>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700360 output_message_modules_and_classes;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800361 for (int i = 0; i < service->method_count(); ++i) {
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000362 const MethodDescriptor* method = service->method(i);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700363 const grpc::string method_description_constructor =
364 grpc::string(method->client_streaming() ? "stream_" : "unary_") +
365 grpc::string(method->server_streaming() ? "stream_" : "unary_") +
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000366 "invocation_description";
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700367 pair<grpc::string, grpc::string> input_message_module_and_class;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000368 if (!GetModuleAndMessagePath(method->input_type(),
369 &input_message_module_and_class)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800370 return false;
371 }
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700372 pair<grpc::string, grpc::string> output_message_module_and_class;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000373 if (!GetModuleAndMessagePath(method->output_type(),
374 &output_message_module_and_class)) {
375 return false;
376 }
377 // Import the modules that define the messages used in RPCs.
378 out->Print("import $Module$\n", "Module",
379 input_message_module_and_class.first);
380 out->Print("import $Module$\n", "Module",
381 output_message_module_and_class.first);
382 method_description_constructors.insert(
383 make_pair(method->name(), method_description_constructor));
384 input_message_modules_and_classes.insert(
385 make_pair(method->name(), input_message_module_and_class));
386 output_message_modules_and_classes.insert(
387 make_pair(method->name(), output_message_module_and_class));
388 }
389 out->Print("method_invocation_descriptions = {\n");
390 for (auto& name_and_description_constructor :
391 method_description_constructors) {
392 IndentScope raii_descriptions_indent(out);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700393 const grpc::string method_name = name_and_description_constructor.first;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000394 auto input_message_module_and_class =
395 input_message_modules_and_classes.find(method_name);
396 auto output_message_module_and_class =
397 output_message_modules_and_classes.find(method_name);
398 out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
399 method_name, "Constructor",
400 name_and_description_constructor.second);
401 {
402 IndentScope raii_description_arguments_indent(out);
403 out->Print(
404 "$InputTypeModule$.$InputTypeClass$.SerializeToString,\n",
405 "InputTypeModule", input_message_module_and_class->second.first,
406 "InputTypeClass", input_message_module_and_class->second.second);
407 out->Print(
408 "$OutputTypeModule$.$OutputTypeClass$.FromString,\n",
409 "OutputTypeModule", output_message_module_and_class->second.first,
410 "OutputTypeClass", output_message_module_and_class->second.second);
411 }
412 out->Print("),\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800413 }
414 out->Print("}\n");
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000415 out->Print(
416 "return implementations.insecure_stub("
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000417 "\"$PackageQualifiedServiceName$\","
418 " method_invocation_descriptions, host, port)\n",
419 "PackageQualifiedServiceName", package_qualified_service_name);
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800420 }
421 return true;
422}
423
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700424bool PrintPreamble(const FileDescriptor* file,
425 const GeneratorConfiguration& config, Printer* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800426 out->Print("import abc\n");
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700427 out->Print("from $Package$ import implementations\n",
428 "Package", config.implementations_package_root);
Masood Malekghassemi89905ac2015-03-17 18:26:48 -0700429 out->Print("from grpc.framework.alpha import utilities\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800430 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800431}
432
433} // namespace
434
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700435pair<bool, grpc::string> GetServices(const FileDescriptor* file,
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700436 const GeneratorConfiguration& config) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700437 grpc::string output;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800438 {
439 // Scope the output stream so it closes and finalizes output to the string.
440 StringOutputStream output_stream(&output);
441 Printer out(&output_stream, '$');
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700442 if (!PrintPreamble(file, config, &out)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800443 return make_pair(false, "");
444 }
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000445 auto package = file->package();
446 if (!package.empty()) {
447 package = package.append(".");
448 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800449 for (int i = 0; i < file->service_count(); ++i) {
450 auto service = file->service(i);
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000451 auto package_qualified_service_name = package + service->name();
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800452 if (!(PrintServicer(service, &out) &&
453 PrintServer(service, &out) &&
454 PrintStub(service, &out) &&
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000455 PrintServerFactory(package_qualified_service_name, service, &out) &&
456 PrintStubFactory(package_qualified_service_name, service, &out))) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800457 return make_pair(false, "");
458 }
459 }
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800460 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800461 return make_pair(true, std::move(output));
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800462}
463
464} // namespace grpc_python_generator