diff options
author | Malar Kannan <malarkannan.invention@gmail.com> | 2019-11-15 06:28:35 +0530 |
---|---|---|
committer | Wouter van Oortmerssen <aardappel@gmail.com> | 2019-11-14 16:58:35 -0800 |
commit | 6beb9f49cb44095c4c17be43f13906c6eb09d7c7 (patch) | |
tree | 37840c903e11db7f048658a6ffd52c2ee41cb7fb /grpc | |
parent | 80988ea869f7bbd5aff9283d49a03e297139ffa2 (diff) | |
download | flatbuffers-6beb9f49cb44095c4c17be43f13906c6eb09d7c7.tar.gz flatbuffers-6beb9f49cb44095c4c17be43f13906c6eb09d7c7.tar.bz2 flatbuffers-6beb9f49cb44095c4c17be43f13906c6eb09d7c7.zip |
Support for python grpc - continuing the work from the pull request #4270 #4705 (#5613)
* Support for python grpc
* add few fixes
* Fixes build
* Fix python generator
* Add tests
* Fix grpc python test
* Fix tests and add incomplete python generator
* Fix python generator
* Add python generator methods
* Fix Appveyor build
* grpc python support v0.1
* Update tests
* update grpctest
* Remove duplicated code and fix a brace
* tests for flatbuffers grpc python
* Updated tests + removed SerializeToString, From String
* remove pickle import
* include missing files in ci - BUILD and generated test result
Diffstat (limited to 'grpc')
-rw-r--r-- | grpc/src/compiler/python_generator.cc | 639 | ||||
-rw-r--r-- | grpc/src/compiler/python_generator.h | 55 | ||||
-rw-r--r-- | grpc/src/compiler/python_private_generator.h | 87 | ||||
-rw-r--r-- | grpc/src/compiler/schema_interface.h | 3 | ||||
-rw-r--r-- | grpc/tests/grpctest.py | 174 |
5 files changed, 958 insertions, 0 deletions
diff --git a/grpc/src/compiler/python_generator.cc b/grpc/src/compiler/python_generator.cc new file mode 100644 index 00000000..4bc2fb5e --- /dev/null +++ b/grpc/src/compiler/python_generator.cc @@ -0,0 +1,639 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cstring> +#include <fstream> +#include <iostream> +#include <map> +#include <memory> +#include <ostream> +#include <set> +#include <sstream> +#include <tuple> +#include <vector> + +#include "flatbuffers/util.h" +#include "src/compiler/python_generator.h" +#include "src/compiler/python_private_generator.h" + +using std::make_pair; +using std::map; +using std::pair; +using std::replace; +using std::tuple; +using std::vector; +using std::set; + +namespace grpc_python_generator { + +grpc::string generator_file_name; + +typedef map<grpc::string, grpc::string> StringMap; +typedef vector<grpc::string> StringVector; +typedef tuple<grpc::string, grpc::string> StringPair; +typedef set<StringPair> StringPairSet; + +// Provides RAII indentation handling. Use as: +// { +// IndentScope raii_my_indent_var_name_here(my_py_printer); +// // constructor indented my_py_printer +// ... +// // destructor called at end of scope, un-indenting my_py_printer +// } +class IndentScope { + public: + explicit IndentScope(grpc_generator::Printer* printer) : printer_(printer) { + printer_->Indent(); + } + + ~IndentScope() { printer_->Outdent(); } + + private: + grpc_generator::Printer* printer_; +}; + +inline grpc::string StringReplace(grpc::string str, const grpc::string& from, + const grpc::string& to, bool replace_all) { + size_t pos = 0; + + do { + pos = str.find(from, pos); + if (pos == grpc::string::npos) { + break; + } + str.replace(pos, from.length(), to); + pos += to.length(); + } while (replace_all); + + return str; +} + +inline grpc::string StringReplace(grpc::string str, const grpc::string& from, + const grpc::string& to) { + return StringReplace(str, from, to, true); +} + +grpc::string ModuleName(const grpc::string& filename, + const grpc::string& import_prefix) { + grpc::string basename = flatbuffers::StripExtension(filename); + basename = StringReplace(basename, "-", "_"); + basename = StringReplace(basename, "/", "."); + return import_prefix + basename + "_fb"; +} + +grpc::string ModuleAlias(const grpc::string& filename, + const grpc::string& import_prefix) { + grpc::string module_name = ModuleName(filename, import_prefix); + // We can't have dots in the module name, so we replace each with _dot_. + // But that could lead to a collision between a.b and a_dot_b, so we also + // duplicate each underscore. + module_name = StringReplace(module_name, "_", "__"); + module_name = StringReplace(module_name, ".", "_dot_"); + return module_name; +} + +PrivateGenerator::PrivateGenerator(const GeneratorConfiguration& config_, + const grpc_generator::File* file_) + : config(config_), file(file_) {} + +void PrivateGenerator::PrintBetaServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(service_dict, "class Beta$Service$Servicer(object):\n"); + { + IndentScope raii_class_indent(out); + out->Print( + "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n" + "\nIt is recommended to use the GA API (classes and functions in this\n" + "file not marked beta) for all further purposes. This class was " + "generated\n" + "only to ease transition from grpcio<0.15.0 to " + "grpcio>=0.15.0.\"\"\"\n"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + grpc::string arg_name = + method->ClientStreaming() ? "request_iterator" : "request"; + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["ArgName"] = arg_name; + out->Print(method_dict, "def $Method$(self, $ArgName$, context):\n"); + { + IndentScope raii_method_indent(out); + out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n"); + } + } + } +} + +void PrivateGenerator::PrintBetaStub(const grpc_generator::Service* service, + grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(service_dict, "class Beta$Service$Stub(object):\n"); + { + IndentScope raii_class_indent(out); + out->Print( + "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n" + "\nIt is recommended to use the GA API (classes and functions in this\n" + "file not marked beta) for all further purposes. This class was " + "generated\n" + "only to ease transition from grpcio<0.15.0 to " + "grpcio>=0.15.0.\"\"\"\n"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + grpc::string arg_name = + method->ClientStreaming() ? "request_iterator" : "request"; + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["ArgName"] = arg_name; + out->Print(method_dict, + "def $Method$(self, $ArgName$, timeout, metadata=None, " + "with_call=False, protocol_options=None):\n"); + { + IndentScope raii_method_indent(out); + out->Print("raise NotImplementedError()\n"); + } + if (!method->ServerStreaming()) { + out->Print(method_dict, "$Method$.future = None\n"); + } + } + } +} + +void PrivateGenerator::PrintBetaServerFactory( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(service_dict, + "def beta_create_$Service$_server(servicer, pool=None, " + "pool_size=None, default_timeout=None, maximum_timeout=None):\n"); + { + IndentScope raii_create_server_indent(out); + out->Print( + "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n" + "\nIt is recommended to use the GA API (classes and functions in this\n" + "file not marked beta) for all further purposes. This function was\n" + "generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0" + "\"\"\"\n"); + StringMap method_implementation_constructors; + StringMap input_message_modules_and_classes; + StringMap output_message_modules_and_classes; + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + const grpc::string method_implementation_constructor = + grpc::string(method->ClientStreaming() ? "stream_" : "unary_") + + grpc::string(method->ServerStreaming() ? "stream_" : "unary_") + + "inline"; + grpc::string input_message_module_and_class = method->get_fb_builder(); + grpc::string output_message_module_and_class = method->get_fb_builder(); + method_implementation_constructors.insert( + make_pair(method->name(), method_implementation_constructor)); + input_message_modules_and_classes.insert( + make_pair(method->name(), input_message_module_and_class)); + output_message_modules_and_classes.insert( + make_pair(method->name(), output_message_module_and_class)); + } + StringMap method_dict; + method_dict["PackageQualifiedServiceName"] = package_qualified_service_name; +// out->Print("request_deserializers = {\n"); +// for (StringMap::iterator name_and_input_module_class_pair = +// input_message_modules_and_classes.begin(); +// name_and_input_module_class_pair != +// input_message_modules_and_classes.end(); +// name_and_input_module_class_pair++) { +// method_dict["MethodName"] = name_and_input_module_class_pair->first; +// method_dict["InputTypeModuleAndClass"] = +// name_and_input_module_class_pair->second; +// IndentScope raii_indent(out); +// out->Print(method_dict, +// "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " +// "$InputTypeModuleAndClass$.FromString,\n"); +// } +// out->Print("}\n"); +// out->Print("response_serializers = {\n"); +// for (StringMap::iterator name_and_output_module_class_pair = +// output_message_modules_and_classes.begin(); +// name_and_output_module_class_pair != +// output_message_modules_and_classes.end(); +// name_and_output_module_class_pair++) { +// method_dict["MethodName"] = name_and_output_module_class_pair->first; +// method_dict["OutputTypeModuleAndClass"] = +// name_and_output_module_class_pair->second; +// IndentScope raii_indent(out); +// out->Print(method_dict, +// "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " +// "$OutputTypeModuleAndClass$.SerializeToString,\n"); +// } +// out->Print("}\n"); + out->Print("method_implementations = {\n"); + for (StringMap::iterator name_and_implementation_constructor = + method_implementation_constructors.begin(); + name_and_implementation_constructor != + method_implementation_constructors.end(); + name_and_implementation_constructor++) { + method_dict["Method"] = name_and_implementation_constructor->first; + method_dict["Constructor"] = name_and_implementation_constructor->second; + IndentScope raii_descriptions_indent(out); + const grpc::string method_name = + name_and_implementation_constructor->first; + out->Print(method_dict, + "(\'$PackageQualifiedServiceName$\', \'$Method$\'): " + "face_utilities.$Constructor$(servicer.$Method$),\n"); + } + out->Print("}\n"); + out->Print( + "server_options = beta_implementations.server_options(" + "thread_pool=pool, thread_pool_size=pool_size, " + "default_timeout=default_timeout, " + "maximum_timeout=maximum_timeout)\n"); + out->Print( + "return beta_implementations.server(method_implementations, " + "options=server_options)\n"); + //"request_deserializers=request_deserializers, " + //"response_serializers=response_serializers, " + } +} + +void PrivateGenerator::PrintBetaStubFactory( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap dict; + dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(dict, + "def beta_create_$Service$_stub(channel, host=None," + " metadata_transformer=None, pool=None, pool_size=None):\n"); + { + IndentScope raii_create_server_indent(out); + out->Print( + "\"\"\"The Beta API is deprecated for 0.15.0 and later.\n" + "\nIt is recommended to use the GA API (classes and functions in this\n" + "file not marked beta) for all further purposes. This function was\n" + "generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0" + "\"\"\"\n"); + StringMap method_cardinalities; + StringMap input_message_modules_and_classes; + StringMap output_message_modules_and_classes; + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + const grpc::string method_cardinality = + grpc::string(method->ClientStreaming() ? "STREAM" : "UNARY") + + "_" + + grpc::string(method->ServerStreaming() ? "STREAM" : "UNARY"); + grpc::string input_message_module_and_class = method->get_fb_builder(); + grpc::string output_message_module_and_class = method->get_fb_builder(); + method_cardinalities.insert( + make_pair(method->name(), method_cardinality)); + input_message_modules_and_classes.insert( + make_pair(method->name(), input_message_module_and_class)); + output_message_modules_and_classes.insert( + make_pair(method->name(), output_message_module_and_class)); + } + StringMap method_dict; + method_dict["PackageQualifiedServiceName"] = package_qualified_service_name; +// out->Print("request_serializers = {\n"); +// for (StringMap::iterator name_and_input_module_class_pair = +// input_message_modules_and_classes.begin(); +// name_and_input_module_class_pair != +// input_message_modules_and_classes.end(); +// name_and_input_module_class_pair++) { +// method_dict["MethodName"] = name_and_input_module_class_pair->first; +// method_dict["InputTypeModuleAndClass"] = +// name_and_input_module_class_pair->second; +// IndentScope raii_indent(out); +// out->Print(method_dict, +// "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " +// "$InputTypeModuleAndClass$.SerializeToString,\n"); +// } +// out->Print("}\n"); +// out->Print("response_deserializers = {\n"); +// for (StringMap::iterator name_and_output_module_class_pair = +// output_message_modules_and_classes.begin(); +// name_and_output_module_class_pair != +// output_message_modules_and_classes.end(); +// name_and_output_module_class_pair++) { +// method_dict["MethodName"] = name_and_output_module_class_pair->first; +// method_dict["OutputTypeModuleAndClass"] = +// name_and_output_module_class_pair->second; +// IndentScope raii_indent(out); +// out->Print(method_dict, +// "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " +// "$OutputTypeModuleAndClass$.FromString,\n"); +// } +// out->Print("}\n"); + out->Print("cardinalities = {\n"); + for (StringMap::iterator name_and_cardinality = + method_cardinalities.begin(); + name_and_cardinality != method_cardinalities.end(); + name_and_cardinality++) { + method_dict["Method"] = name_and_cardinality->first; + method_dict["Cardinality"] = name_and_cardinality->second; + IndentScope raii_descriptions_indent(out); + out->Print(method_dict, + "\'$Method$\': cardinality.Cardinality.$Cardinality$,\n"); + } + out->Print("}\n"); + out->Print( + "stub_options = beta_implementations.stub_options(" + "host=host, metadata_transformer=metadata_transformer, " + "thread_pool=pool, thread_pool_size=pool_size)\n"); + out->Print(method_dict, + "return beta_implementations.dynamic_stub(channel, " + "\'$PackageQualifiedServiceName$\', " + "cardinalities, options=stub_options)\n"); + // "request_serializers=request_serializers, " + //"response_deserializers=response_deserializers, " + } +} + +void PrivateGenerator::PrintStub( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap dict; + dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(dict, "class $Service$Stub(object):\n"); + { + IndentScope raii_class_indent(out); + out->Print("\n"); + out->Print("def __init__(self, channel):\n"); + { + IndentScope raii_init_indent(out); + out->Print("\"\"\"Constructor.\n"); + out->Print("\n"); + out->Print("Args:\n"); + { + IndentScope raii_args_indent(out); + out->Print("channel: A grpc.Channel.\n"); + } + out->Print("\"\"\"\n"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + grpc::string multi_callable_constructor = + grpc::string(method->ClientStreaming() ? "stream" : "unary") + + "_" + + grpc::string(method->ServerStreaming() ? "stream" : "unary"); + grpc::string request_module_and_class = method->get_fb_builder(); + grpc::string response_module_and_class = method->get_fb_builder(); + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["MultiCallableConstructor"] = multi_callable_constructor; + out->Print(method_dict, + "self.$Method$ = channel.$MultiCallableConstructor$(\n"); + { + method_dict["PackageQualifiedService"] = + package_qualified_service_name; + method_dict["RequestModuleAndClass"] = request_module_and_class; + method_dict["ResponseModuleAndClass"] = response_module_and_class; + IndentScope raii_first_attribute_indent(out); + IndentScope raii_second_attribute_indent(out); + out->Print(method_dict, "'/$PackageQualifiedService$/$Method$',\n"); + out->Print(method_dict,"\n"); + out->Print( + method_dict,"\n"); + out->Print(")\n"); + } + } + } + } +} + +void PrivateGenerator::PrintServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(service_dict, "class $Service$Servicer(object):\n"); + { + IndentScope raii_class_indent(out); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + grpc::string arg_name = + method->ClientStreaming() ? "request_iterator" : "request"; + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["ArgName"] = arg_name; + out->Print("\n"); + out->Print(method_dict, "def $Method$(self, $ArgName$, context):\n"); + { + IndentScope raii_method_indent(out); + out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n"); + out->Print("context.set_details('Method not implemented!')\n"); + out->Print("raise NotImplementedError('Method not implemented!')\n"); + } + } + } +} + +void PrivateGenerator::PrintAddServicerToServer( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); + out->Print("\n\n"); + out->Print(service_dict, + "def add_$Service$Servicer_to_server(servicer, server):\n"); + { + IndentScope raii_class_indent(out); + out->Print("rpc_method_handlers = {\n"); + { + IndentScope raii_dict_first_indent(out); + IndentScope raii_dict_second_indent(out); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + grpc::string method_handler_constructor = + grpc::string(method->ClientStreaming() ? "stream" : "unary") + + "_" + + grpc::string(method->ServerStreaming() ? "stream" : "unary") + + "_rpc_method_handler"; + grpc::string request_module_and_class = method->get_fb_builder(); + grpc::string response_module_and_class = method->get_fb_builder(); + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["MethodHandlerConstructor"] = method_handler_constructor; + method_dict["RequestModuleAndClass"] = request_module_and_class; + method_dict["ResponseModuleAndClass"] = response_module_and_class; + out->Print(method_dict, + "'$Method$': grpc.$MethodHandlerConstructor$(\n"); + { + IndentScope raii_call_first_indent(out); + IndentScope raii_call_second_indent(out); + out->Print(method_dict, "servicer.$Method$,\n"); + out->Print( + method_dict,"\n"); + out->Print( + method_dict, + "\n"); + } + out->Print("),\n"); + } + } + StringMap method_dict; + method_dict["PackageQualifiedServiceName"] = package_qualified_service_name; + out->Print("}\n"); + out->Print("generic_handler = grpc.method_handlers_generic_handler(\n"); + { + IndentScope raii_call_first_indent(out); + IndentScope raii_call_second_indent(out); + out->Print(method_dict, + "'$PackageQualifiedServiceName$', rpc_method_handlers)\n"); + } + out->Print("server.add_generic_rpc_handlers((generic_handler,))\n"); + } +} + +void PrivateGenerator::PrintBetaPreamble(grpc_generator::Printer* out) { + StringMap var; + var["Package"] = config.beta_package_root; + out->Print(var, + "from $Package$ import implementations as beta_implementations\n"); + out->Print(var, "from $Package$ import interfaces as beta_interfaces\n"); + out->Print("from grpc.framework.common import cardinality\n"); + out->Print( + "from grpc.framework.interfaces.face import utilities as " + "face_utilities\n"); +} + +void PrivateGenerator::PrintPreamble(grpc_generator::Printer* out) { + StringMap var; + var["Package"] = config.grpc_package_root; + out->Print(var, "import $Package$\n"); + out->Print("\n"); + StringPairSet imports_set; + for (int i = 0; i < file->service_count(); ++i) { + auto service = file->service(i); + for (int j = 0; j < service->method_count(); ++j) { + auto method = service.get()->method(j); + + grpc::string input_type_file_name = method->get_fb_builder(); + grpc::string input_module_name = + ModuleName(input_type_file_name, config.import_prefix); + grpc::string input_module_alias = + ModuleAlias(input_type_file_name, config.import_prefix); + imports_set.insert( + std::make_tuple(input_module_name, input_module_alias)); + + grpc::string output_type_file_name = method->get_fb_builder(); + grpc::string output_module_name = + ModuleName(output_type_file_name, config.import_prefix); + grpc::string output_module_alias = + ModuleAlias(output_type_file_name, config.import_prefix); + imports_set.insert( + std::make_tuple(output_module_name, output_module_alias)); + } + } + + for (StringPairSet::iterator it = imports_set.begin(); + it != imports_set.end(); ++it) { + var["ModuleName"] = std::get<0>(*it); + var["ModuleAlias"] = std::get<1>(*it); + out->Print(var, "import $ModuleName$ as $ModuleAlias$\n"); + } +} + +void PrivateGenerator::PrintGAServices(grpc_generator::Printer* out) { + grpc::string package = file->package(); + if (!package.empty()) { + package = package.append("."); + } + + out->Print(file->additional_headers().c_str()); + + for (int i = 0; i < file->service_count(); ++i) { + auto service = file->service(i); + + grpc::string package_qualified_service_name = package + service->name(); + PrintStub(package_qualified_service_name, service.get(), out); + PrintServicer(service.get(), out); + PrintAddServicerToServer(package_qualified_service_name, service.get(), + out); + } +} + +void PrivateGenerator::PrintBetaServices(grpc_generator::Printer* out) { + grpc::string package = file->package(); + if (!package.empty()) { + package = package.append("."); + } + for (int i = 0; i < file->service_count(); ++i) { + auto service = file->service(i); + + grpc::string package_qualified_service_name = package + service->name(); + PrintBetaServicer(service.get(), out); + PrintBetaStub(service.get(), out); + PrintBetaServerFactory(package_qualified_service_name, service.get(), out); + PrintBetaStubFactory(package_qualified_service_name, service.get(), out); + } +} + +grpc::string PrivateGenerator::GetGrpcServices() { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto out = file->CreatePrinter(&output); + out->Print( + "# Generated by the gRPC Python protocol compiler plugin. " + "DO NOT EDIT!\n"); + StringMap var; + var["Package"] = config.grpc_package_root; + out->Print(var, "import $Package$\n"); + PrintGAServices(out.get()); + out->Print("try:\n"); + { + IndentScope raii_dict_try_indent(out.get()); + out->Print( + "# THESE ELEMENTS WILL BE DEPRECATED.\n" + "# Please use the generated *_pb2_grpc.py files instead.\n"); + out->Print(var, "import $Package$\n"); + PrintBetaPreamble(out.get()); + PrintGAServices(out.get()); + PrintBetaServices(out.get()); + } + out->Print("except ImportError:\n"); + { + IndentScope raii_dict_except_indent(out.get()); + out->Print("pass"); + } + } + return output; +} + +} // namespace grpc_python_generator diff --git a/grpc/src/compiler/python_generator.h b/grpc/src/compiler/python_generator.h new file mode 100644 index 00000000..8e3af8a2 --- /dev/null +++ b/grpc/src/compiler/python_generator.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H + +#include <utility> + +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +// Data pertaining to configuration of the generator with respect to anything +// that may be used internally at Google. +struct GeneratorConfiguration { + grpc::string grpc_package_root; + // TODO(https://github.com/grpc/grpc/issues/8622): Drop this. + grpc::string beta_package_root; + // TODO(https://github.com/google/protobuf/issues/888): Drop this. + grpc::string import_prefix; +}; + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H diff --git a/grpc/src/compiler/python_private_generator.h b/grpc/src/compiler/python_private_generator.h new file mode 100644 index 00000000..f070145c --- /dev/null +++ b/grpc/src/compiler/python_private_generator.h @@ -0,0 +1,87 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H + +#include <iostream> +#include <vector> + +#include "src/compiler/python_generator.h" +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +// Tucks all generator state in an anonymous namespace away from +// PythonGrpcGenerator and the header file, mostly to encourage future changes +// to not require updates to the grpcio-tools C++ code part. Assumes that it is +// only ever used from a single thread. +struct PrivateGenerator { + const GeneratorConfiguration& config; + const grpc_generator::File* file; + + PrivateGenerator(const GeneratorConfiguration& config, + const grpc_generator::File* file); + + grpc::string GetGrpcServices(); + + private: + void PrintPreamble(grpc_generator::Printer* out); + void PrintBetaPreamble(grpc_generator::Printer* out); + void PrintGAServices(grpc_generator::Printer* out); + void PrintBetaServices(grpc_generator::Printer* out); + + void PrintAddServicerToServer( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out); + void PrintServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out); + void PrintStub(const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + + void PrintBetaServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out); + void PrintBetaServerFactory( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out); + void PrintBetaStub(const grpc_generator::Service* service, + grpc_generator::Printer* out); + void PrintBetaStubFactory(const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); +}; + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H diff --git a/grpc/src/compiler/schema_interface.h b/grpc/src/compiler/schema_interface.h index 638448d3..52060bc5 100644 --- a/grpc/src/compiler/schema_interface.h +++ b/grpc/src/compiler/schema_interface.h @@ -79,6 +79,9 @@ struct Method : public CommentHolder { virtual grpc::string get_input_type_name() const = 0; virtual grpc::string get_output_type_name() const = 0; + + virtual grpc::string get_fb_builder() const = 0; + virtual bool NoStreaming() const = 0; virtual bool ClientStreaming() const = 0; virtual bool ServerStreaming() const = 0; diff --git a/grpc/tests/grpctest.py b/grpc/tests/grpctest.py new file mode 100644 index 00000000..1c5e92f0 --- /dev/null +++ b/grpc/tests/grpctest.py @@ -0,0 +1,174 @@ +from __future__ import print_function + +import os +import sys +import grpc +import flatbuffers + +from concurrent import futures + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'tests')) +import MyGame.Example.Monster as Monster +import MyGame.Example.Stat as Stat +import MyGame.Example.Vec3 as Vec3 +import MyGame.Example.Test as Test +import MyGame.Example.monster_test_grpc_fb as monster_grpc_fb + + +test_stat_id = "test_stat_id" +test_stat_val = 8 +test_stat_count = 1 + +test_monster_name1 = "test_monster_name1" +test_monster_name2 = "test_monster_name2" +test_string = "test_string" +test_color = 2 +test_X = 3.0 +test_Y = 2.0 +test_Z = 6.0 +test_test1 = 4.0 +test_a = 8 +test_b = 5 +test_hp = 67 +test_inventory = [1, 1, 2, 3, 5, 8] +test_testtype = 4 + +test_monsters_name_retrieve = ["big_monster", "small_monster"] +test_no_of_monsters = 2 + + +class MonsterStorage(monster_grpc_fb.MonsterStorageServicer): + + def Store(self, request, context): + + m = Monster.Monster().GetRootAsMonster(request, 0) + + assert m.Name().decode("utf-8") == test_monster_name1 + + assert m.Pos().X() == test_X + assert m.Pos().Y() == test_Y + assert m.Pos().Z() == test_Z + assert m.Pos().Test1() == test_test1 + assert m.Pos().Test2() == test_color + test3 = Test.Test() + assert m.Pos().Test3(test3).A() == test_a + assert m.Pos().Test3(test3).B() == test_b + + assert m.Hp() == test_hp + + assert m.Color() == test_color + + assert m.InventoryLength() == len(test_inventory) + for i in range(0, len(test_inventory)): + assert m.Inventory(i) == test_inventory[len(test_inventory)-i -1] + + assert m.TestType() == test_testtype + + assert m.Test() is not None + table = m.Test() + + m2 = Monster.Monster() + m2.Init(table.Bytes, table.Pos) + assert m2.Name().decode("utf-8") == test_monster_name2 + + m3 = m.Enemy() + assert m3.Name().decode("utf-8") == test_monster_name2 + + assert m.Testarrayofstring(0).decode("utf-8") == test_string + + b = flatbuffers.Builder(0) + i = b.CreateString(test_stat_id) + Stat.StatStart(b) + Stat.StatAddId(b, i) + Stat.StatAddVal(b, test_stat_val) + Stat.StatAddCount(b, test_stat_count) + b.Finish(Stat.StatEnd(b)) + return bytes(b.Output()) + + def Retrieve(self, request, context): + + s = Stat.Stat().GetRootAsStat(request, 0) + + no_of_monsters = test_no_of_monsters + for i in range(0, no_of_monsters): + b = flatbuffers.Builder(0) + i = b.CreateString(test_monsters_name_retrieve[i]) + Monster.MonsterStart(b) + Monster.MonsterAddName(b, i) + b.Finish(Monster.MonsterEnd(b)) + yield bytes(b.Output()) + + +def serve(): + + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + monster_grpc_fb.add_MonsterStorageServicer_to_server(MonsterStorage(), server) + server.add_insecure_port('[::]:50051') + + server.start() + + run() + + +def run(): + + channel = grpc.insecure_channel('127.0.0.1:50051') + stub = monster_grpc_fb.MonsterStorageStub(channel) + + b = flatbuffers.Builder(0) + name2 = b.CreateString(test_monster_name2) + name1 = b.CreateString(test_monster_name1) + Monster.MonsterStart(b) + Monster.MonsterAddName(b, name2) + monster2 = Monster.MonsterEnd(b) + test1 = b.CreateString(test_string) + + Monster.MonsterStartInventoryVector(b, len(test_inventory)) + for i in range(0, len(test_inventory)): + b.PrependByte(test_inventory[i]) + inv = b.EndVector(len(test_inventory)) + + Monster.MonsterStartTest4Vector(b, 2) + Test.CreateTest(b, 10, 20) + Test.CreateTest(b, 30, 40) + test4 = b.EndVector(2) + + Monster.MonsterStartTestarrayofstringVector(b, 1) + b.PrependUOffsetTRelative(test1) + test_array_of_string = b.EndVector(1) + + Monster.MonsterStart(b) + + Monster.MonsterAddHp(b, test_hp) + Monster.MonsterAddName(b, name1) + Monster.MonsterAddColor(b, test_color) + pos = Vec3.CreateVec3(b, test_X, test_Y, test_Z, test_test1, test_color, test_a, test_b) + Monster.MonsterAddPos(b, pos) + Monster.MonsterAddInventory(b, inv) + Monster.MonsterAddTestType(b, test_testtype) + Monster.MonsterAddTest(b, monster2) + Monster.MonsterAddTest4(b, test4) + Monster.MonsterAddEnemy(b, monster2) + Monster.MonsterAddTestarrayofstring(b, test_array_of_string) + monster = Monster.MonsterEnd(b) + + b.Finish(monster) + + stat_response = stub.Store(bytes(b.Output())) + + s = Stat.Stat().GetRootAsStat(stat_response, 0) + + assert s.Id().decode("utf-8") == test_stat_id + assert s.Val() == test_stat_val + assert s.Count() == test_stat_count + + monster_reponses = stub.Retrieve(stat_response) + count = 0 + for monster_reponse in monster_reponses: + m = Monster.Monster().GetRootAsMonster(monster_reponse, 0) + assert m.Name().decode("utf-8") == test_monsters_name_retrieve[count] + count = count + 1 + + +if __name__ == '__main__': + serve() |