|  | @@ -28,6 +28,9 @@ import sys
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from grpc_tools import _protoc_compiler
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +_PROTO_MODULE_SUFFIX = "_pb2"
 | 
	
		
			
				|  |  | +_SERVICE_MODULE_SUFFIX = "_pb2_grpc"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  def main(command_arguments):
 | 
	
		
			
				|  |  |      """Run the protocol buffer compiler with the given command-line arguments.
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -65,7 +68,7 @@ def _augmented_syspath(new_paths):
 | 
	
		
			
				|  |  |  def get_protos(protobuf_path, include_paths=None):
 | 
	
		
			
				|  |  |    with _augmented_syspath(include_paths):
 | 
	
		
			
				|  |  |      # TODO: Pull these strings out to module-level constants.
 | 
	
		
			
				|  |  | -    module_name = _proto_file_to_module_name("_pb2", protobuf_path)
 | 
	
		
			
				|  |  | +    module_name = _proto_file_to_module_name(_PROTO_MODULE_SUFFIX, protobuf_path)
 | 
	
		
			
				|  |  |      module = importlib.import_module(module_name)
 | 
	
		
			
				|  |  |      return module
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -73,7 +76,7 @@ def get_protos(protobuf_path, include_paths=None):
 | 
	
		
			
				|  |  |  def get_services(protobuf_path, include_paths=None):
 | 
	
		
			
				|  |  |    get_protos(protobuf_path, include_paths)
 | 
	
		
			
				|  |  |    with _augmented_syspath(include_paths):
 | 
	
		
			
				|  |  | -    module_name = _proto_file_to_module_name("_pb2_grpc", protobuf_path)
 | 
	
		
			
				|  |  | +    module_name = _proto_file_to_module_name(_SERVICE_MODULE_SUFFIX, protobuf_path)
 | 
	
		
			
				|  |  |      module = importlib.import_module(module_name)
 | 
	
		
			
				|  |  |      return module
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -83,13 +86,12 @@ def get_protos_and_services(protobuf_path, include_paths=None):
 | 
	
		
			
				|  |  |            get_services(protobuf_path, include_paths=include_paths))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  _proto_code_cache = {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class ProtoLoader(importlib.abc.Loader):
 | 
	
		
			
				|  |  | -  def __init__(self, suffix, code_fn, module_name, protobuf_path, proto_root):
 | 
	
		
			
				|  |  | +  def __init__(self, suffix, codegen_fn, module_name, protobuf_path, proto_root):
 | 
	
		
			
				|  |  |      self._suffix = suffix
 | 
	
		
			
				|  |  | -    self._code_fn = code_fn
 | 
	
		
			
				|  |  | +    self._codegen_fn = codegen_fn
 | 
	
		
			
				|  |  |      self._module_name = module_name
 | 
	
		
			
				|  |  |      self._protobuf_path = protobuf_path
 | 
	
		
			
				|  |  |      self._proto_root = proto_root
 | 
	
	
		
			
				|  | @@ -98,7 +100,7 @@ class ProtoLoader(importlib.abc.Loader):
 | 
	
		
			
				|  |  |      return None
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def _generated_file_to_module_name(self, filepath):
 | 
	
		
			
				|  |  | -    components = filepath.split("/")
 | 
	
		
			
				|  |  | +    components = filepath.split(os.path.sep)
 | 
	
		
			
				|  |  |      return ".".join(components[:-1] + [os.path.splitext(components[-1])[0]])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def exec_module(self, module):
 | 
	
	
		
			
				|  | @@ -108,7 +110,12 @@ class ProtoLoader(importlib.abc.Loader):
 | 
	
		
			
				|  |  |        code = _proto_code_cache[self._module_name]
 | 
	
		
			
				|  |  |        six.exec_(code, module.__dict__)
 | 
	
		
			
				|  |  |      else:
 | 
	
		
			
				|  |  | -      files = self._code_fn(self._protobuf_path.encode('ascii'), [path.encode('ascii') for path in sys.path])
 | 
	
		
			
				|  |  | +      files = self._codegen_fn(self._protobuf_path.encode('ascii'), [path.encode('ascii') for path in sys.path])
 | 
	
		
			
				|  |  | +      # NOTE: The files are returned in topological order of dependencies. Each
 | 
	
		
			
				|  |  | +      # entry is guaranteed to depend only on the modules preceding it in the
 | 
	
		
			
				|  |  | +      # list and the last entry is guaranteed to be our requested module. We
 | 
	
		
			
				|  |  | +      # cache the code from the first invocation at module-scope so that we
 | 
	
		
			
				|  |  | +      # don't have to regenerate code that has already been generated by protoc.
 | 
	
		
			
				|  |  |        for f in files[:-1]:
 | 
	
		
			
				|  |  |          module_name = self._generated_file_to_module_name(f[0].decode('ascii'))
 | 
	
		
			
				|  |  |          if module_name not in sys.modules:
 | 
	
	
		
			
				|  | @@ -119,9 +126,9 @@ class ProtoLoader(importlib.abc.Loader):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class ProtoFinder(importlib.abc.MetaPathFinder):
 | 
	
		
			
				|  |  | -  def __init__(self, suffix, code_fn):
 | 
	
		
			
				|  |  | +  def __init__(self, suffix, codegen_fn):
 | 
	
		
			
				|  |  |      self._suffix = suffix
 | 
	
		
			
				|  |  | -    self._code_fn = code_fn
 | 
	
		
			
				|  |  | +    self._codegen_fn = codegen_fn
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def find_spec(self, fullname, path, target=None):
 | 
	
		
			
				|  |  |      filepath = _module_name_to_proto_file(self._suffix, fullname)
 | 
	
	
		
			
				|  | @@ -133,9 +140,10 @@ class ProtoFinder(importlib.abc.MetaPathFinder):
 | 
	
		
			
				|  |  |          continue
 | 
	
		
			
				|  |  |        else:
 | 
	
		
			
				|  |  |          # TODO: Use a stdlib helper function to construct this.
 | 
	
		
			
				|  |  | -        return importlib.machinery.ModuleSpec(fullname, ProtoLoader(self._suffix, self._code_fn, fullname, filepath, search_path))
 | 
	
		
			
				|  |  | +        return importlib.machinery.ModuleSpec(fullname, ProtoLoader(self._suffix, self._codegen_fn, fullname, filepath, search_path))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -sys.meta_path.extend([ProtoFinder("_pb2", _protoc_compiler.get_protos), ProtoFinder("_pb2_grpc", _protoc_compiler.get_services)])
 | 
	
		
			
				|  |  | +sys.meta_path.extend([ProtoFinder(_PROTO_MODULE_SUFFIX, _protoc_compiler.get_protos),
 | 
	
		
			
				|  |  | +                      ProtoFinder(_SERVICE_MODULE_SUFFIX, _protoc_compiler.get_services)])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  if __name__ == '__main__':
 | 
	
		
			
				|  |  |      proto_include = pkg_resources.resource_filename('grpc_tools', '_proto')
 |