【问题标题】:Generating python client from a .proto with (well-known) timestamp从带有(众所周知的)时间戳的 .proto 生成 python 客户端
【发布时间】:2018-04-03 20:18:46
【问题描述】:

当我拿一个简单的hello.proto 文件时

syntax = "proto3";
package helloworld;
//import "timestamp.proto";
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
  string name = 1;
  //google.protobuf.Timestamp smth = 2;
}
message HelloReply {
  string message = 1;
}

并且(在virtualenv -p python3 py内)使用

生成python代码
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./hello.proto

我得到了两个不错的文件:hello_pb2.pyhello_pb2_grpc.py

还有一个简单的两行playground.py:

import hello_pb2
import hello_pb2_grpc

python playground.py 配合得很好

一切都会改变,当尝试使用众所周知的 protobuf 类型、时间戳和取消注释第 3 行和第 9 行时。


我在站点包中看到的最接近的对应文件timestamp.proto

$ find -name timestamp\*
./lib/python3.5/site-packages/grpc_tools/_proto/google/protobuf/timestamp.proto
./lib/python3.5/site-packages/google/protobuf/timestamp_pb2.py
./lib/python3.5/site-packages/google/protobuf/__pycache__/timestamp_pb2.cpython-35.pyc

所以我使用了一些不同的代码生成命令:

python -m grpc_tools.protoc -I. \
       -I./lib/python3.5/site-packages/grpc_tools/_proto/google/protobuf \
       --python_out=. --grpc_python_out=. ./hello.proto

python playground.py 现在会导致错误:

Traceback (most recent call last):
  File "playground.py", line 1, in <module>
    import hello_pb2
  File "/py/hello_pb2.py", line 16, in <module>
    import timestamp_pb2 as timestamp__pb2
ImportError: No module named 'timestamp_pb2

那是因为hello_pb2.py 现在有一行:

import timestamp_pb2 as timestamp__pb2

我尝试了一些不同的 playground.py:

import sys
sys.path.append('./lib/python3.5/site-packages/google/protobuf')
import hello_pb2
import hello_pb2_grpc

但这会导致不同的错误:

$ python playground.py 
Traceback (most recent call last):
  File "playground.py", line 3, in <module>
    import hello_pb2
  File "/py/hello_pb2.py", line 25, in <module>
    dependencies=[timestamp__pb2.DESCRIPTOR,])
  File "/py/lib/python3.5/site-packages/google/protobuf/descriptor.py", line 829, in __new__
    return _message.default_pool.AddSerializedFile(serialized_pb)
TypeError: Couldn't build proto file into descriptor pool!
Invalid proto descriptor for file "hello.proto":
  hello.proto: Import "timestamp.proto" has not been loaded.
  helloworld.HelloRequest.smth: "google.protobuf.Timestamp" seems to be defined in "google/protobuf/timestamp.proto", which is not imported by "hello.proto".  To use it here, please add the necessary import.

所以,我没有想法。如何在python中使用这个众所周知的类型(3)?


详细信息:ubuntu:xenial、python 3.5.2、virtualenv 15.2.0、 env:virtualenv -p python3 py &amp;&amp; cd py &amp;&amp; source bin/activate &amp;&amp; pip install grpcio grpcio_tools(这会安装 protobuf-3.5.2、grpcio-1.10.0、grpcio_tools-1.10.0)

【问题讨论】:

  • 我怀疑这更像是一个 Protocol Buffers Python 问题而不是一个 gRPC Python 问题(从你的命令行中取出 --grpc_python_out=.,我敢打赌你的问题仍然存在)但我会接受一个镜头:你为什么认为你需要“import timestamp.proto;”在您的.proto 文件中?你能只取消第 9 行的注释并看到一切正常吗?
  • 当我单独取消注释第 9 行时,我在生成期间得到hello.proto:9:3: "google.protobuf.Timestamp" is not defined.。 (但谢谢)

标签: python python-3.x protocol-buffers grpc


【解决方案1】:

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

这不应该使用 Python grpc_tools 发生,但是对于 protoc 的其他发行版,protoc 可能会抱怨,它不知道 "google/protobuf/timestamp.proto" 在哪里。在这种情况下,您需要使用 -I 标志指定内置 protobuf 文件的根目录。

为什么会这样?

根据我对 protoc 的经验(又名。未通过文档或源代码确认),看起来当 .proto 文件编译为 Python 时,.proto 中的 import 语句从:

import "path/to/file.proto";

收件人:

import path.to.file_pb2

protobuf 编译器不会尝试解析文件的位置(这是有道理的,因为它不知道您的 Python 环境,也不知道其他已编译的 .proto 文件在哪里)。

截至 2018 年 4 月 9 日,pip grpc 包包括来自 google.protobuf 包的内置 protobuf 类型。这就是为什么我们希望我们的导入包含 google/protobuf 前缀。

旁注

如果您希望编译后的 .proto 项目的根目录与 Python 项目的根目录不同(例如,您可能希望将所有原型存储在 protos 包中),Protobuf 的导入解析可能会特别烦人。到目前为止,我发现的唯一解决方案是:

  • 破解 protoc 并将新根添加到所有导入语句(例如,将 import "path/to/file.proto" 更改为 import "protos/path/to/file.proto")。这可以在每次编译之前以编程方式完成。

  • 将已编译的 proto 项目的根添加到 Python 路径:

    import sys
    sys.path.append('path/to/protos_root/')
    

【讨论】:

  • 这使得hello_pb2.py 中的导入行变成from google.protobuf import timestamp_pb2 as ... 我的直觉在哪里......(谢谢)
  • @bohdan_trotsenko 完全正确。请参阅我编辑的答案以获取有关此的更多信息。请记住,所有这些信息都是基于我对 protobuf 的实验,而不是基于记录的功能(但我很确定它是正确的)。
猜你喜欢
  • 1970-01-01
  • 2022-01-06
  • 2018-02-03
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
相关资源
最近更新 更多