blob: fe2b9fad99beaa8b7cec3936174309d4353ed198 [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
yang-g9e2f90c2015-08-21 15:35:03 -070045#include <grpc++/support/config.h>
Masood Malekghassemi65c803b2015-03-20 06:48:47 -070046#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
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000151bool PrintAlphaServicer(const ServiceDescriptor* service,
152 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
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000179bool PrintAlphaServer(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
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000207bool PrintAlphaStub(const ServiceDescriptor* service,
208 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();
Vijay Paic0897432015-07-27 22:18:13 +0000252 } while (path_elem_type); // implicit nullptr comparison; don't be explicit
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
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000271bool PrintAlphaServerFactory(const grpc::string& package_qualified_service_name,
272 const ServiceDescriptor* service, Printer* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800273 out->Print("def early_adopter_create_$Service$_server(servicer, port, "
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000274 "private_key=None, certificate_chain=None):\n",
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800275 "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");
Vijay Pai82dd80a2015-03-24 10:36:08 -0700312 for (auto name_and_description_constructor =
313 method_description_constructors.begin();
314 name_and_description_constructor !=
315 method_description_constructors.end();
316 name_and_description_constructor++) {
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000317 IndentScope raii_descriptions_indent(out);
Vijay Pai82dd80a2015-03-24 10:36:08 -0700318 const grpc::string method_name = name_and_description_constructor->first;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000319 auto input_message_module_and_class =
320 input_message_modules_and_classes.find(method_name);
321 auto output_message_module_and_class =
322 output_message_modules_and_classes.find(method_name);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000323 out->Print("\"$Method$\": alpha_utilities.$Constructor$(\n", "Method",
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000324 method_name, "Constructor",
Vijay Pai82dd80a2015-03-24 10:36:08 -0700325 name_and_description_constructor->second);
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000326 {
327 IndentScope raii_description_arguments_indent(out);
328 out->Print("servicer.$Method$,\n", "Method", method_name);
329 out->Print(
330 "$InputTypeModule$.$InputTypeClass$.FromString,\n",
331 "InputTypeModule", input_message_module_and_class->second.first,
332 "InputTypeClass", input_message_module_and_class->second.second);
333 out->Print(
334 "$OutputTypeModule$.$OutputTypeClass$.SerializeToString,\n",
335 "OutputTypeModule", output_message_module_and_class->second.first,
336 "OutputTypeClass", output_message_module_and_class->second.second);
337 }
338 out->Print("),\n");
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800339 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800340 out->Print("}\n");
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000341 out->Print(
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000342 "return implementations.server("
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000343 "\"$PackageQualifiedServiceName$\","
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000344 " method_service_descriptions, port, private_key=private_key,"
345 " certificate_chain=certificate_chain)\n",
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000346 "PackageQualifiedServiceName", package_qualified_service_name);
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800347 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800348 return true;
349}
350
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000351bool PrintAlphaStubFactory(const grpc::string& package_qualified_service_name,
352 const ServiceDescriptor* service, Printer* out) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700353 map<grpc::string, grpc::string> dict = ListToDict({
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800354 "Service", service->name(),
355 });
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000356 out->Print(dict, "def early_adopter_create_$Service$_stub(host, port,"
Nathaniel Manistacd7096d2015-04-06 15:08:36 +0000357 " metadata_transformer=None,"
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000358 " secure=False, root_certificates=None, private_key=None,"
359 " certificate_chain=None, server_host_override=None):\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800360 {
361 IndentScope raii_create_server_indent(out);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700362 map<grpc::string, grpc::string> method_description_constructors;
363 map<grpc::string, pair<grpc::string, grpc::string>>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700364 input_message_modules_and_classes;
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700365 map<grpc::string, pair<grpc::string, grpc::string>>
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700366 output_message_modules_and_classes;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800367 for (int i = 0; i < service->method_count(); ++i) {
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000368 const MethodDescriptor* method = service->method(i);
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700369 const grpc::string method_description_constructor =
370 grpc::string(method->client_streaming() ? "stream_" : "unary_") +
371 grpc::string(method->server_streaming() ? "stream_" : "unary_") +
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000372 "invocation_description";
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700373 pair<grpc::string, grpc::string> input_message_module_and_class;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000374 if (!GetModuleAndMessagePath(method->input_type(),
375 &input_message_module_and_class)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800376 return false;
377 }
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700378 pair<grpc::string, grpc::string> output_message_module_and_class;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000379 if (!GetModuleAndMessagePath(method->output_type(),
380 &output_message_module_and_class)) {
381 return false;
382 }
383 // Import the modules that define the messages used in RPCs.
384 out->Print("import $Module$\n", "Module",
385 input_message_module_and_class.first);
386 out->Print("import $Module$\n", "Module",
387 output_message_module_and_class.first);
388 method_description_constructors.insert(
389 make_pair(method->name(), method_description_constructor));
390 input_message_modules_and_classes.insert(
391 make_pair(method->name(), input_message_module_and_class));
392 output_message_modules_and_classes.insert(
393 make_pair(method->name(), output_message_module_and_class));
394 }
395 out->Print("method_invocation_descriptions = {\n");
Vijay Pai82dd80a2015-03-24 10:36:08 -0700396 for (auto name_and_description_constructor =
397 method_description_constructors.begin();
398 name_and_description_constructor !=
399 method_description_constructors.end();
400 name_and_description_constructor++) {
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000401 IndentScope raii_descriptions_indent(out);
Vijay Pai82dd80a2015-03-24 10:36:08 -0700402 const grpc::string method_name = name_and_description_constructor->first;
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000403 auto input_message_module_and_class =
404 input_message_modules_and_classes.find(method_name);
405 auto output_message_module_and_class =
406 output_message_modules_and_classes.find(method_name);
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000407 out->Print("\"$Method$\": alpha_utilities.$Constructor$(\n", "Method",
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000408 method_name, "Constructor",
Vijay Pai82dd80a2015-03-24 10:36:08 -0700409 name_and_description_constructor->second);
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000410 {
411 IndentScope raii_description_arguments_indent(out);
412 out->Print(
413 "$InputTypeModule$.$InputTypeClass$.SerializeToString,\n",
414 "InputTypeModule", input_message_module_and_class->second.first,
415 "InputTypeClass", input_message_module_and_class->second.second);
416 out->Print(
417 "$OutputTypeModule$.$OutputTypeClass$.FromString,\n",
418 "OutputTypeModule", output_message_module_and_class->second.first,
419 "OutputTypeClass", output_message_module_and_class->second.second);
420 }
421 out->Print("),\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800422 }
423 out->Print("}\n");
Nathaniel Manistaa60a77b2015-03-02 08:30:49 +0000424 out->Print(
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000425 "return implementations.stub("
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000426 "\"$PackageQualifiedServiceName$\","
Nathaniel Manistacd7096d2015-04-06 15:08:36 +0000427 " method_invocation_descriptions, host, port,"
428 " metadata_transformer=metadata_transformer, secure=secure,"
Nathaniel Manistaf492b162015-03-30 18:14:52 +0000429 " root_certificates=root_certificates, private_key=private_key,"
430 " certificate_chain=certificate_chain,"
431 " server_host_override=server_host_override)\n",
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000432 "PackageQualifiedServiceName", package_qualified_service_name);
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800433 }
434 return true;
435}
436
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000437bool PrintBetaServicer(const ServiceDescriptor* service,
438 Printer* out) {
439 grpc::string doc = "<fill me in later!>";
440 map<grpc::string, grpc::string> dict = ListToDict({
441 "Service", service->name(),
442 "Documentation", doc,
443 });
444 out->Print("\n");
445 out->Print(dict, "class Beta$Service$Servicer(object):\n");
446 {
447 IndentScope raii_class_indent(out);
448 out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
449 out->Print("__metaclass__ = abc.ABCMeta\n");
450 for (int i = 0; i < service->method_count(); ++i) {
451 auto meth = service->method(i);
452 grpc::string arg_name = meth->client_streaming() ?
453 "request_iterator" : "request";
454 out->Print("@abc.abstractmethod\n");
455 out->Print("def $Method$(self, $ArgName$, context):\n",
456 "Method", meth->name(), "ArgName", arg_name);
457 {
458 IndentScope raii_method_indent(out);
459 out->Print("raise NotImplementedError()\n");
460 }
461 }
462 }
463 return true;
464}
465
466bool PrintBetaStub(const ServiceDescriptor* service,
467 Printer* out) {
468 grpc::string doc = "The interface to which stubs will conform.";
469 map<grpc::string, grpc::string> dict = ListToDict({
470 "Service", service->name(),
471 "Documentation", doc,
472 });
473 out->Print("\n");
474 out->Print(dict, "class Beta$Service$Stub(object):\n");
475 {
476 IndentScope raii_class_indent(out);
477 out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
478 out->Print("__metaclass__ = abc.ABCMeta\n");
479 for (int i = 0; i < service->method_count(); ++i) {
480 const MethodDescriptor* meth = service->method(i);
481 grpc::string arg_name = meth->client_streaming() ?
482 "request_iterator" : "request";
483 auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
484 out->Print("@abc.abstractmethod\n");
485 out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
486 {
487 IndentScope raii_method_indent(out);
488 out->Print("raise NotImplementedError()\n");
489 }
490 if (!meth->server_streaming()) {
491 out->Print(methdict, "$Method$.future = None\n");
492 }
493 }
494 }
495 return true;
496}
497
498bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
499 const ServiceDescriptor* service, Printer* out) {
500 out->Print("\n");
501 out->Print("def beta_create_$Service$_server(servicer, pool=None, "
502 "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
503 "Service", service->name());
504 {
505 IndentScope raii_create_server_indent(out);
506 map<grpc::string, grpc::string> method_implementation_constructors;
507 map<grpc::string, pair<grpc::string, grpc::string>>
508 input_message_modules_and_classes;
509 map<grpc::string, pair<grpc::string, grpc::string>>
510 output_message_modules_and_classes;
511 for (int i = 0; i < service->method_count(); ++i) {
512 const MethodDescriptor* method = service->method(i);
513 const grpc::string method_implementation_constructor =
514 grpc::string(method->client_streaming() ? "stream_" : "unary_") +
515 grpc::string(method->server_streaming() ? "stream_" : "unary_") +
516 "inline";
517 pair<grpc::string, grpc::string> input_message_module_and_class;
518 if (!GetModuleAndMessagePath(method->input_type(),
519 &input_message_module_and_class)) {
520 return false;
521 }
522 pair<grpc::string, grpc::string> output_message_module_and_class;
523 if (!GetModuleAndMessagePath(method->output_type(),
524 &output_message_module_and_class)) {
525 return false;
526 }
527 // Import the modules that define the messages used in RPCs.
528 out->Print("import $Module$\n", "Module",
529 input_message_module_and_class.first);
530 out->Print("import $Module$\n", "Module",
531 output_message_module_and_class.first);
532 method_implementation_constructors.insert(
533 make_pair(method->name(), method_implementation_constructor));
534 input_message_modules_and_classes.insert(
535 make_pair(method->name(), input_message_module_and_class));
536 output_message_modules_and_classes.insert(
537 make_pair(method->name(), output_message_module_and_class));
538 }
539 out->Print("request_deserializers = {\n");
540 for (auto name_and_input_module_class_pair =
541 input_message_modules_and_classes.begin();
542 name_and_input_module_class_pair !=
543 input_message_modules_and_classes.end();
544 name_and_input_module_class_pair++) {
545 IndentScope raii_indent(out);
546 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
547 "$InputTypeModule$.$InputTypeClass$.FromString,\n",
548 "PackageQualifiedServiceName", package_qualified_service_name,
549 "MethodName", name_and_input_module_class_pair->first,
550 "InputTypeModule",
551 name_and_input_module_class_pair->second.first,
552 "InputTypeClass",
553 name_and_input_module_class_pair->second.second);
554 }
555 out->Print("}\n");
556 out->Print("response_serializers = {\n");
557 for (auto name_and_output_module_class_pair =
558 output_message_modules_and_classes.begin();
559 name_and_output_module_class_pair !=
560 output_message_modules_and_classes.end();
561 name_and_output_module_class_pair++) {
562 IndentScope raii_indent(out);
563 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
564 "$OutputTypeModule$.$OutputTypeClass$.SerializeToString,\n",
565 "PackageQualifiedServiceName", package_qualified_service_name,
566 "MethodName", name_and_output_module_class_pair->first,
567 "OutputTypeModule",
568 name_and_output_module_class_pair->second.first,
569 "OutputTypeClass",
570 name_and_output_module_class_pair->second.second);
571 }
572 out->Print("}\n");
573 out->Print("method_implementations = {\n");
574 for (auto name_and_implementation_constructor =
575 method_implementation_constructors.begin();
576 name_and_implementation_constructor !=
577 method_implementation_constructors.end();
578 name_and_implementation_constructor++) {
579 IndentScope raii_descriptions_indent(out);
580 const grpc::string method_name =
581 name_and_implementation_constructor->first;
582 out->Print("(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
583 "face_utilities.$Constructor$(servicer.$Method$),\n",
584 "PackageQualifiedServiceName", package_qualified_service_name,
585 "Method", name_and_implementation_constructor->first,
586 "Constructor", name_and_implementation_constructor->second);
587 }
588 out->Print("}\n");
589 out->Print("server_options = beta.server_options("
590 "request_deserializers=request_deserializers, "
591 "response_serializers=response_serializers, "
592 "thread_pool=pool, thread_pool_size=pool_size, "
593 "default_timeout=default_timeout, "
594 "maximum_timeout=maximum_timeout)\n");
595 out->Print("return beta.server(method_implementations, "
596 "options=server_options)\n");
597 }
598 return true;
599}
600
601bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
602 const ServiceDescriptor* service, Printer* out) {
603 map<grpc::string, grpc::string> dict = ListToDict({
604 "Service", service->name(),
605 });
606 out->Print("\n");
607 out->Print(dict, "def beta_create_$Service$_stub(channel, host=None,"
608 " metadata_transformer=None, pool=None, pool_size=None):\n");
609 {
610 IndentScope raii_create_server_indent(out);
611 map<grpc::string, grpc::string> method_cardinalities;
612 map<grpc::string, pair<grpc::string, grpc::string>>
613 input_message_modules_and_classes;
614 map<grpc::string, pair<grpc::string, grpc::string>>
615 output_message_modules_and_classes;
616 for (int i = 0; i < service->method_count(); ++i) {
617 const MethodDescriptor* method = service->method(i);
618 const grpc::string method_cardinality =
619 grpc::string(method->client_streaming() ? "STREAM" : "UNARY") +
620 "_" +
621 grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
622 pair<grpc::string, grpc::string> input_message_module_and_class;
623 if (!GetModuleAndMessagePath(method->input_type(),
624 &input_message_module_and_class)) {
625 return false;
626 }
627 pair<grpc::string, grpc::string> output_message_module_and_class;
628 if (!GetModuleAndMessagePath(method->output_type(),
629 &output_message_module_and_class)) {
630 return false;
631 }
632 // Import the modules that define the messages used in RPCs.
633 out->Print("import $Module$\n", "Module",
634 input_message_module_and_class.first);
635 out->Print("import $Module$\n", "Module",
636 output_message_module_and_class.first);
637 method_cardinalities.insert(
638 make_pair(method->name(), method_cardinality));
639 input_message_modules_and_classes.insert(
640 make_pair(method->name(), input_message_module_and_class));
641 output_message_modules_and_classes.insert(
642 make_pair(method->name(), output_message_module_and_class));
643 }
644 out->Print("request_serializers = {\n");
645 for (auto name_and_input_module_class_pair =
646 input_message_modules_and_classes.begin();
647 name_and_input_module_class_pair !=
648 input_message_modules_and_classes.end();
649 name_and_input_module_class_pair++) {
650 IndentScope raii_indent(out);
651 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
652 "$InputTypeModule$.$InputTypeClass$.SerializeToString,\n",
653 "PackageQualifiedServiceName", package_qualified_service_name,
654 "MethodName", name_and_input_module_class_pair->first,
655 "InputTypeModule",
656 name_and_input_module_class_pair->second.first,
657 "InputTypeClass",
658 name_and_input_module_class_pair->second.second);
659 }
660 out->Print("}\n");
661 out->Print("response_deserializers = {\n");
662 for (auto name_and_output_module_class_pair =
663 output_message_modules_and_classes.begin();
664 name_and_output_module_class_pair !=
665 output_message_modules_and_classes.end();
666 name_and_output_module_class_pair++) {
667 IndentScope raii_indent(out);
668 out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
669 "$OutputTypeModule$.$OutputTypeClass$.FromString,\n",
670 "PackageQualifiedServiceName", package_qualified_service_name,
671 "MethodName", name_and_output_module_class_pair->first,
672 "OutputTypeModule",
673 name_and_output_module_class_pair->second.first,
674 "OutputTypeClass",
675 name_and_output_module_class_pair->second.second);
676 }
677 out->Print("}\n");
678 out->Print("cardinalities = {\n");
679 for (auto name_and_cardinality = method_cardinalities.begin();
680 name_and_cardinality != method_cardinalities.end();
681 name_and_cardinality++) {
682 IndentScope raii_descriptions_indent(out);
683 out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
684 "Method", name_and_cardinality->first,
685 "Cardinality", name_and_cardinality->second);
686 }
687 out->Print("}\n");
688 out->Print("stub_options = beta.stub_options("
689 "host=host, metadata_transformer=metadata_transformer, "
690 "request_serializers=request_serializers, "
691 "response_deserializers=response_deserializers, "
692 "thread_pool=pool, thread_pool_size=pool_size)\n");
693 out->Print(
694 "return beta.dynamic_stub(channel, \'$PackageQualifiedServiceName$\', "
695 "cardinalities, options=stub_options)\n",
696 "PackageQualifiedServiceName", package_qualified_service_name);
697 }
698 return true;
699}
700
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700701bool PrintPreamble(const FileDescriptor* file,
702 const GeneratorConfiguration& config, Printer* out) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800703 out->Print("import abc\n");
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000704 out->Print("from $Package$ import beta\n",
705 "Package", config.beta_package_root);
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700706 out->Print("from $Package$ import implementations\n",
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000707 "Package", config.early_adopter_package_root);
708 out->Print("from grpc.framework.alpha import utilities as alpha_utilities\n");
709 out->Print("from grpc.framework.common import cardinality\n");
710 out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800711 return true;
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800712}
713
714} // namespace
715
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700716pair<bool, grpc::string> GetServices(const FileDescriptor* file,
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700717 const GeneratorConfiguration& config) {
Masood Malekghassemi65c803b2015-03-20 06:48:47 -0700718 grpc::string output;
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800719 {
720 // Scope the output stream so it closes and finalizes output to the string.
721 StringOutputStream output_stream(&output);
722 Printer out(&output_stream, '$');
Masood Malekghassemi3bb52152015-03-17 21:52:52 -0700723 if (!PrintPreamble(file, config, &out)) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800724 return make_pair(false, "");
725 }
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000726 auto package = file->package();
727 if (!package.empty()) {
728 package = package.append(".");
729 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800730 for (int i = 0; i < file->service_count(); ++i) {
731 auto service = file->service(i);
Nathaniel Manistac4fada62015-03-13 22:23:59 +0000732 auto package_qualified_service_name = package + service->name();
Nathaniel Manistacd9ec0e2015-08-31 07:49:45 +0000733 if (!(PrintAlphaServicer(service, &out) &&
734 PrintAlphaServer(service, &out) &&
735 PrintAlphaStub(service, &out) &&
736 PrintAlphaServerFactory(package_qualified_service_name, service, &out) &&
737 PrintAlphaStubFactory(package_qualified_service_name, service, &out) &&
738 PrintBetaServicer(service, &out) &&
739 PrintBetaStub(service, &out) &&
740 PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
741 PrintBetaStubFactory(package_qualified_service_name, service, &out))) {
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800742 return make_pair(false, "");
743 }
744 }
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800745 }
Masood Malekghassemi59d9ff42015-02-23 15:28:07 -0800746 return make_pair(true, std::move(output));
Masood Malekghassemif8e297a2015-02-19 15:39:32 -0800747}
748
749} // namespace grpc_python_generator