@ -1,6 +1,5 @@
""" Generates and compiles Python gRPC stubs from proto_library rules. """
""" Generates and compiles Python gRPC stubs from proto_library rules. """
load ( " @grpc_python_dependencies//:requirements.bzl " , " requirement " )
load (
load (
" //bazel:protobuf.bzl " ,
" //bazel:protobuf.bzl " ,
" get_include_protoc_args " ,
" get_include_protoc_args " ,
@ -36,56 +35,33 @@ def _generate_py_impl(context):
for file in src [ ProtoInfo ] . transitive_imports . to_list ( )
for file in src [ ProtoInfo ] . transitive_imports . to_list ( )
]
]
proto_root = get_proto_root ( context . label . workspace_root )
proto_root = get_proto_root ( context . label . workspace_root )
format_str = ( _GENERATED_GRPC_PROTO_FORMAT if context . executable . plugin else _GENERATED_PROTO_FORMAT )
out_files = [
out_files = [
context . actions . declare_file (
context . actions . declare_file (
proto_path_to_generated_filename (
proto_path_to_generated_filename (
proto . basename ,
proto . basename ,
format_str ,
_GENERATED_PROTO_FORMAT ,
) ,
) ,
)
)
for proto in protos
for proto in protos
]
]
arguments = [ ]
tools = [ context . executable . _protoc ]
tools = [ context . executable . _protoc ]
if context . executable . plugin :
arguments = ( [
arguments + = get_plugin_args (
" --python_out= {} " . format (
context . executable . plugin ,
context . attr . flags ,
context . genfiles_dir . path ,
context . genfiles_dir . path ,
False ,
) ,
)
] + get_include_protoc_args ( includes ) + [
tools + = [ context . executable . plugin ]
else :
arguments + = [
" --python_out= {} : {} " . format (
" , " . join ( context . attr . flags ) ,
context . genfiles_dir . path ,
) ,
]
arguments + = get_include_protoc_args ( includes )
arguments + = [
" --proto_path= {} " . format ( context . genfiles_dir . path )
" --proto_path= {} " . format ( context . genfiles_dir . path )
for proto in protos
for proto in protos
]
] )
for proto in protos :
for proto in protos :
massaged_path = proto . path
massaged_path = proto . path
if massaged_path . startswith ( context . genfiles_dir . path ) :
if massaged_path . startswith ( context . genfiles_dir . path ) :
massaged_path = proto . path [ len ( context . genfiles_dir . path ) + 1 : ]
massaged_path = proto . path [ len ( context . genfiles_dir . path ) + 1 : ]
arguments . append ( massaged_path )
arguments . append ( massaged_path )
well_known_proto_files = [ ]
if context . attr . well_known_protos :
well_known_proto_directory = context . attr . well_known_protos . files . to_list (
) [ 0 ] . dirname
arguments + = [ " -I {} " . format ( well_known_proto_directory + " /../.. " ) ]
well_known_proto_files = context . attr . well_known_protos . files . to_list ( )
context . actions . run (
context . actions . run (
inputs = protos + includes + well_known_proto_files ,
inputs = protos + includes ,
tools = tools ,
tools = tools ,
outputs = out_files ,
outputs = out_files ,
executable = context . executable . _protoc ,
executable = context . executable . _protoc ,
@ -94,93 +70,155 @@ def _generate_py_impl(context):
)
)
return struct ( files = depset ( out_files ) )
return struct ( files = depset ( out_files ) )
__generate_py = rule (
_generate_pb2_src = rule (
attrs = {
attrs = {
" deps " : attr . label_list (
" deps " : attr . label_list (
mandatory = True ,
mandatory = True ,
allow_empty = False ,
allow_empty = False ,
providers = [ ProtoInfo ] ,
providers = [ ProtoInfo ] ,
) ,
) ,
" plugin " : attr . label (
executable = True ,
providers = [ " files_to_run " ] ,
cfg = " host " ,
) ,
" flags " : attr . string_list (
mandatory = False ,
allow_empty = True ,
) ,
" well_known_protos " : attr . label ( mandatory = False ) ,
" _protoc " : attr . label (
" _protoc " : attr . label (
default = Label ( " //external:protocol_compiler " ) ,
default = Label ( " //external:protocol_compiler " ) ,
providers = [ " files_to_run " ] ,
executable = True ,
executable = True ,
cfg = " host " ,
cfg = " host " ,
) ,
) ,
} ,
} ,
output_to_genfiles = True ,
implementation = _generate_py_impl ,
implementation = _generate_py_impl ,
)
)
def _generate_py ( well_known_protos , * * kwargs ) :
if well_known_protos :
__generate_py (
well_known_protos = " @com_google_protobuf//:well_known_protos " ,
* * kwargs
)
else :
__generate_py ( * * kwargs )
def py_proto_library (
def py_proto_library (
name ,
name ,
deps ,
srcs ,
well_known_protos = True ,
proto_only = False ,
* * kwargs ) :
* * kwargs ) :
""" Generate python code for a protobuf.
""" Generate python code for a protobuf.
Args :
Args :
name : The name of the target .
name : The name of the target .
deps : A list of dependencies . Must contain a single element .
srcs : A list of proto_library dependencies . Must contain a single element .
well_known_protos : A bool indicating whether or not to include well - known
protos .
proto_only : A bool indicating whether to generate vanilla protobuf code
or to also generate gRPC code .
"""
"""
if len ( deps ) > 1 :
fail ( " The supported length of ' deps ' is 1. " )
codegen_target = " _ {} _codegen " . format ( name )
codegen_target = " _ {} _codegen " . format ( name )
codegen_grpc_target = " _ {} _grpc_codegen " . format ( name )
if len ( srcs ) > 1 :
fail ( " Can only compile a single proto at a time. " )
_generate_py (
_generate_pb2_src (
name = codegen_target ,
name = codegen_target ,
deps = deps ,
deps = srcs ,
well_known_protos = well_known_protos ,
* * kwargs
* * kwargs
)
)
if not proto_only :
native . py_library (
_generate_py (
name = name ,
name = codegen_grpc_target ,
srcs = [ " : {} " . format ( codegen_target ) ] ,
deps = deps ,
deps = [ " @com_google_protobuf//:protobuf_python " ] ,
plugin = " //src/compiler:grpc_python_plugin " ,
* * kwargs
well_known_protos = well_known_protos ,
)
* * kwargs
)
native . py_library (
def _generate_pb2_grpc_src_impl ( context ) :
name = name ,
protos = [ ]
srcs = [
for src in context . attr . deps :
" : {} " . format ( codegen_grpc_target ) ,
for file in src [ ProtoInfo ] . direct_sources :
" : {} " . format ( codegen_target ) ,
protos . append ( _get_staged_proto_file ( context , file ) )
] ,
includes = [
deps = [ requirement ( " protobuf " ) ] ,
file
* * kwargs
for src in context . attr . deps
)
for file in src [ ProtoInfo ] . transitive_imports . to_list ( )
else :
]
native . py_library (
proto_root = get_proto_root ( context . label . workspace_root )
name = name ,
out_files = [
srcs = [ " : {} " . format ( codegen_target ) , " : {} " . format ( codegen_target ) ] ,
context . actions . declare_file (
deps = [ requirement ( " protobuf " ) ] ,
proto_path_to_generated_filename (
* * kwargs
proto . basename ,
_GENERATED_GRPC_PROTO_FORMAT ,
) ,
)
)
for proto in protos
]
arguments = [ ]
tools = [ context . executable . _protoc , context . executable . _plugin ]
arguments + = get_plugin_args (
context . executable . _plugin ,
[ ] ,
context . genfiles_dir . path ,
False ,
)
arguments + = get_include_protoc_args ( includes )
arguments + = [
" --proto_path= {} " . format ( context . genfiles_dir . path )
for proto in protos
]
for proto in protos :
massaged_path = proto . path
if massaged_path . startswith ( context . genfiles_dir . path ) :
massaged_path = proto . path [ len ( context . genfiles_dir . path ) + 1 : ]
arguments . append ( massaged_path )
context . actions . run (
inputs = protos + includes ,
tools = tools ,
outputs = out_files ,
executable = context . executable . _protoc ,
arguments = arguments ,
mnemonic = " ProtocInvocation " ,
)
return struct ( files = depset ( out_files ) )
_generate_pb2_grpc_src = rule (
attrs = {
" deps " : attr . label_list (
mandatory = True ,
allow_empty = False ,
providers = [ ProtoInfo ] ,
) ,
" _plugin " : attr . label (
executable = True ,
providers = [ " files_to_run " ] ,
cfg = " host " ,
default = Label ( " //src/compiler:grpc_python_plugin " ) ,
) ,
" _protoc " : attr . label (
executable = True ,
providers = [ " files_to_run " ] ,
cfg = " host " ,
default = Label ( " //external:protocol_compiler " ) ,
) ,
} ,
implementation = _generate_pb2_grpc_src_impl ,
)
def py_grpc_library (
name ,
srcs ,
deps ,
* * kwargs ) :
""" Generate python code for gRPC services defined in a protobuf.
Args :
name : The name of the target .
srcs : ( List of ` labels ` ) a single proto_library target containing the
schema of the service .
deps : ( List of ` labels ` ) a single py_proto_library target for the
proto_library in ` srcs ` .
"""
codegen_grpc_target = " _ {} _grpc_codegen " . format ( name )
if len ( srcs ) > 1 :
fail ( " Can only compile a single proto at a time. " )
_generate_pb2_grpc_src (
name = codegen_grpc_target ,
deps = srcs ,
* * kwargs
)
native . py_library (
name = name ,
srcs = [
" : {} " . format ( codegen_grpc_target ) ,
] ,
deps = [ Label ( " //src/python/grpcio/grpc:grpcio " ) ] + deps ,
* * kwargs
)