如何让 protoc 编译带有依赖项的 proto?

bas*_*hig 5 protocol-buffers protoc

我需要修复 grpc 服务,所以我想了解编译它们的逻辑。

在下面的示例中,我不明白为什么 protoc 不编译address.proto,因为它是由person.proto.

没有构建错误,所以我认为这不是导入/命名问题。不幸的是,只person_pb2.py生成了一个...

// file: address.proto

syntax="proto3";

message Address {
    string city = 1;
    string road = 3;
    int32 roadNumber = 4;
}
Run Code Online (Sandbox Code Playgroud)
// file: person.proto

syntax="proto3";

import "address.proto";

message Person {
  string name = 1;
  Address home = 3;
  Address work = 4;
}
Run Code Online (Sandbox Code Playgroud)

构建命令:

python -m grpc_tools.protoc --proto_path ../protos --python_out=. person.proto
Run Code Online (Sandbox Code Playgroud)

Daz*_*kin 2

这是一个合理的问题。

答案是,您只是要求protoc编译person.proto(并且它会字面意思)。但是,生成的代码将无法运行,因为person_pb2.py取决于address_pb2

import address_pb2 as address__pb2
Run Code Online (Sandbox Code Playgroud)

您需要拥有代码所需的所有协议缓冲区类型的 Python 源代码。

python3 \
-m grpc_tools.protoc \
--proto_path=../protos \
--python_out=. \
person.proto address.proto
Run Code Online (Sandbox Code Playgroud)

这个问题(正在解决)的一个很好的例子是 Google 所谓的众所周知的类型(WKT)

您可以通过添加以下google.protobuf.Timestamp内容来包含例如:Personimport "google/protobuf/timestamp.proto"

syntax="proto3";

import "google/protobuf/timestamp.proto";
import "address.proto";

message Person {
  string name = 1;
  Address home = 3;
  Address work = 4;
  google.protobuf.Timestamp timestamp = 5;
}
Run Code Online (Sandbox Code Playgroud)

您无需进行protoc 任何更改,您的代码就可以工作。

这是因为 Google 将 WKT生成的 Python 代码与grpcio-tool. 与任何其他源一样,您确实需要导入 Google 提供的 Python 源才能使用代码。

为此,您必须

main.py:

import address_pb2
import person_pb2

from google.protobuf.timestamp_pb2 import Timestamp
Run Code Online (Sandbox Code Playgroud)

那么,这些文件在哪里?

就我而言:

lib/python3.8/site-packages/grpc_tools/_proto/google/protobuf/timestamp.proto
Run Code Online (Sandbox Code Playgroud)

和:

lib/python3.8/site-packages/google/protobuf/timestamp_pb2.py
Run Code Online (Sandbox Code Playgroud)

注意
Google 捆绑生成的源代码很方便,但这不是必需的,而且会产生两个潜在的问题。

  1. timestamp.proto是真理的来源,我们必须相信它google/protobuf/timestamp_pb2.py是由它产生的。
  2. 如果我们是原型开发人员,我们需要为原型开发人员每次更新原型时可能使用的所有语言生成源代码。

由于这些原因,通常(!)开发人员只提供原型,不包括生成的源,并假设您能够将原型插入protoc并自己生成完美的传真作为代码。