Skip to content

Commit

Permalink
Python GA code generation
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanielmanistaatgoogle committed Jun 13, 2016
1 parent 55ca239 commit 4547940
Show file tree
Hide file tree
Showing 7 changed files with 853 additions and 3 deletions.
148 changes: 146 additions & 2 deletions src/compiler/python_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
out->Print("}\n");
out->Print("method_implementations = {\n");
for (auto name_and_implementation_constructor =
method_implementation_constructors.begin();
method_implementation_constructors.begin();
name_and_implementation_constructor !=
method_implementation_constructors.end();
name_and_implementation_constructor++) {
Expand Down Expand Up @@ -457,8 +457,149 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
return true;
}

bool PrintStub(const grpc::string& package_qualified_service_name,
const ServiceDescriptor* service, Printer* out) {
out->Print("\n\n");
out->Print("class $Service$Stub(object):\n", "Service", service->name());
{
IndentScope raii_class_indent(out);
PrintAllComments(service, 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);
auto multi_callable_constructor =
grpc::string(method->client_streaming() ? "stream" : "unary") +
"_" +
grpc::string(method->server_streaming() ? "stream" : "unary");
grpc::string request_module_and_class;
if (!GetModuleAndMessagePath(method->input_type(), service,
&request_module_and_class)) {
return false;
}
grpc::string response_module_and_class;
if (!GetModuleAndMessagePath(method->output_type(), service,
&response_module_and_class)) {
return false;
}
out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
"Method", method->name(),
"MultiCallableConstructor", multi_callable_constructor);
{
IndentScope raii_first_attribute_indent(out);
IndentScope raii_second_attribute_indent(out);
out->Print(
"'/$PackageQualifiedService$/$Method$',\n",
"PackageQualifiedService", package_qualified_service_name,
"Method", method->name());
out->Print(
"request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
"RequestModuleAndClass", request_module_and_class);
out->Print(
"response_deserializer=$ResponseModuleAndClass$.FromString,\n",
"ResponseModuleAndClass", response_module_and_class);
out->Print(")\n");
}
}
}
}
return true;
}

bool PrintServicer(const ServiceDescriptor* service, Printer* out) {
out->Print("\n\n");
out->Print("class $Service$Servicer(object):\n", "Service", service->name());
{
IndentScope raii_class_indent(out);
PrintAllComments(service, out);
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
grpc::string arg_name = method->client_streaming() ?
"request_iterator" : "request";
out->Print("\n");
out->Print("def $Method$(self, $ArgName$, context):\n",
"Method", method->name(), "ArgName", arg_name);
{
IndentScope raii_method_indent(out);
PrintAllComments(method, 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");
}
}
}
return true;
}

bool PrintAddServicerToServer(const grpc::string& package_qualified_service_name,
const ServiceDescriptor* service, Printer* out) {
out->Print("\n\n");
out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
"Service", service->name());
{
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);
auto method_handler_constructor =
grpc::string(method->client_streaming() ? "stream" : "unary") +
"_" +
grpc::string(method->server_streaming() ? "stream" : "unary") +
"_rpc_method_handler";
grpc::string request_module_and_class;
if (!GetModuleAndMessagePath(method->input_type(), service,
&request_module_and_class)) {
return false;
}
grpc::string response_module_and_class;
if (!GetModuleAndMessagePath(method->output_type(), service,
&response_module_and_class)) {
return false;
}
out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n",
"Method", method->name(),
"MethodHandlerConstructor", method_handler_constructor);
{
IndentScope raii_call_first_indent(out);
IndentScope raii_call_second_indent(out);
out->Print("servicer.$Method$,\n", "Method", method->name());
out->Print("request_deserializer=$RequestModuleAndClass$.FromString,\n",
"RequestModuleAndClass", request_module_and_class);
out->Print("response_serializer=$ResponseModuleAndClass$.SerializeToString,\n",
"ResponseModuleAndClass", response_module_and_class);
}
out->Print("),\n");
}
}
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("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
"PackageQualifiedServiceName", package_qualified_service_name);
}
out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
}
return true;
}

bool PrintPreamble(const FileDescriptor* file,
const GeneratorConfiguration& config, Printer* out) {
out->Print("import $Package$\n", "Package", config.grpc_package_root);
out->Print("from $Package$ import implementations as beta_implementations\n",
"Package", config.beta_package_root);
out->Print("from $Package$ import interfaces as beta_interfaces\n",
Expand Down Expand Up @@ -487,7 +628,10 @@ pair<bool, grpc::string> GetServices(const FileDescriptor* file,
for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i);
auto package_qualified_service_name = package + service->name();
if (!(PrintBetaServicer(service, &out) &&
if (!(PrintStub(package_qualified_service_name, service, &out) &&
PrintServicer(service, &out) &&
PrintAddServicerToServer(package_qualified_service_name, service, &out) &&
PrintBetaServicer(service, &out) &&
PrintBetaStub(service, &out) &&
PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
PrintBetaStubFactory(package_qualified_service_name, service, &out))) {
Expand Down
1 change: 1 addition & 0 deletions src/compiler/python_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ 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;
grpc::string beta_package_root;
};

Expand Down
1 change: 1 addition & 0 deletions src/compiler/python_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

int main(int argc, char* argv[]) {
grpc_python_generator::GeneratorConfiguration config;
config.grpc_package_root = "grpc";
config.beta_package_root = "grpc.beta";
grpc_python_generator::PythonGrpcGenerator generator(config);
return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
Expand Down
96 changes: 96 additions & 0 deletions src/python/grpcio/grpc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,102 @@ def stop(self, grace):
################################# Functions ################################


def unary_unary_rpc_method_handler(
behavior, request_deserializer=None, response_serializer=None):
"""Creates an RpcMethodHandler for a unary-unary RPC method.
Args:
behavior: The implementation of an RPC method as a callable behavior taking
a single request value and returning a single response value.
request_deserializer: An optional request deserialization behavior.
response_serializer: An optional response serialization behavior.
Returns:
An RpcMethodHandler for a unary-unary RPC method constructed from the given
parameters.
"""
from grpc import _utilities
return _utilities.RpcMethodHandler(
False, False, request_deserializer, response_serializer, behavior, None,
None, None)


def unary_stream_rpc_method_handler(
behavior, request_deserializer=None, response_serializer=None):
"""Creates an RpcMethodHandler for a unary-stream RPC method.
Args:
behavior: The implementation of an RPC method as a callable behavior taking
a single request value and returning an iterator of response values.
request_deserializer: An optional request deserialization behavior.
response_serializer: An optional response serialization behavior.
Returns:
An RpcMethodHandler for a unary-stream RPC method constructed from the
given parameters.
"""
from grpc import _utilities
return _utilities.RpcMethodHandler(
False, True, request_deserializer, response_serializer, None, behavior,
None, None)


def stream_unary_rpc_method_handler(
behavior, request_deserializer=None, response_serializer=None):
"""Creates an RpcMethodHandler for a stream-unary RPC method.
Args:
behavior: The implementation of an RPC method as a callable behavior taking
an iterator of request values and returning a single response value.
request_deserializer: An optional request deserialization behavior.
response_serializer: An optional response serialization behavior.
Returns:
An RpcMethodHandler for a stream-unary RPC method constructed from the
given parameters.
"""
from grpc import _utilities
return _utilities.RpcMethodHandler(
True, False, request_deserializer, response_serializer, None, None,
behavior, None)


def stream_stream_rpc_method_handler(
behavior, request_deserializer=None, response_serializer=None):
"""Creates an RpcMethodHandler for a stream-stream RPC method.
Args:
behavior: The implementation of an RPC method as a callable behavior taking
an iterator of request values and returning an iterator of response
values.
request_deserializer: An optional request deserialization behavior.
response_serializer: An optional response serialization behavior.
Returns:
An RpcMethodHandler for a stream-stream RPC method constructed from the
given parameters.
"""
from grpc import _utilities
return _utilities.RpcMethodHandler(
True, True, request_deserializer, response_serializer, None, None, None,
behavior)


def method_handlers_generic_handler(service, method_handlers):
"""Creates a grpc.GenericRpcHandler from RpcMethodHandlers.
Args:
service: A service name to be used for the given method handlers.
method_handlers: A dictionary from method name to RpcMethodHandler
implementing the named method.
Returns:
A GenericRpcHandler constructed from the given parameters.
"""
from grpc import _utilities
return _utilities.DictionaryGenericHandler(service, method_handlers)


def ssl_channel_credentials(
root_certificates=None, private_key=None, certificate_chain=None):
"""Creates a ChannelCredentials for use with an SSL-enabled Channel.
Expand Down
26 changes: 25 additions & 1 deletion src/python/grpcio/grpc/_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,41 @@

"""Internal utilities for gRPC Python."""

import collections
import threading
import time

import six

import grpc
from grpc import _common
from grpc.framework.foundation import callable_util

_DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = (
'Exception calling connectivity future "done" callback!')


class RpcMethodHandler(
collections.namedtuple(
'_RpcMethodHandler',
('request_streaming', 'response_streaming', 'request_deserializer',
'response_serializer', 'unary_unary', 'unary_stream', 'stream_unary',
'stream_stream',)),
grpc.RpcMethodHandler):
pass


class DictionaryGenericHandler(grpc.GenericRpcHandler):

def __init__(self, service, method_handlers):
self._method_handlers = {
_common.fully_qualified_method(service, method): method_handler
for method, method_handler in six.iteritems(method_handlers)}

def service(self, handler_call_details):
return self._method_handlers.get(handler_call_details.method)


class _ChannelReadyFuture(grpc.Future):

def __init__(self, channel):
Expand Down Expand Up @@ -144,4 +169,3 @@ def channel_ready_future(channel):
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future

Loading

0 comments on commit 4547940

Please sign in to comment.