10

protobuf 是否支持 python 的相对导入?

我未能成功创建支持此功能的 protobuf 构建脚本。从我的 .proto 文件生成 python 类时,如果我从创建生成的 .py 文件的同一文件夹中启动 python,我只能导入 python 模块。

我已经构建了以下 MVP。理想情况下,我想要一个结构,其中生成的 python 代码放置在一个单独的文件夹(例如./generated)中,然后我可以将其移动到其他项目中。我已经发布了我已经开始工作的方法,但我希望更有经验的人能够为我指出更好的解决方案。

基本信息:

  • Python 3.6.8
  • protobuf 3.11.3

文件夹结构:

.
|--- schemas
     |---- main_class.proto
     |---- sub
           |----sub_class.proto
|--- generated

尝试 1:相对导入

main_class.proto:

syntax = "proto3";

import public "sub/sub_class.proto";

message MainClass {
    repeated SubClass subclass = 1;
}

sub_class.proto:

syntax = "proto3";

message LogMessage {
    enum Status {
        STATUS_ERROR = 0;
        STATUS_OK = 1;
    }

    Status status = 1;
    string timestamp = 2;
}

message SubClass {
    string name = 1;
    repeated LogMessage log = 2;
}

协议命令:

从根文件夹:

protoc -I=schemas --python_out=generated main_class.proto sub/sub_class.proto

这会将 python 文件放在./generated文件夹中。

什么有效,什么无效

使用上面的方法,我可以在文件夹中启动 python./generated并使用导入

import main_class_pb2 as MC_proto.

.但是,当我从根文件夹(或任何其他文件夹)启动 python 时,使用导入

import generated.main_class_pb2 as MC_proto

产生错误ModuleNotFoundError: No module named 'sub'。基于this post,我手动修改生成的main_class_pb2.py-file如下

# Original
# from sub import sub_class_pb2 as sub_dot_sub__class__pb2
# from sub.sub_class_pb2 import *

# Fix
from .sub import sub_class_pb2 as sub_dot_sub__class__pb2
from .sub.sub_class_pb2 import *

.通过在导入语句的开头添加in,我现在可以使用import generated.main_class_pb2 as MC_proto. 但是,每次都必须手动编辑生成的文件是非常不切实际的,所以我不喜欢这种方法。

尝试 2:绝对进口

我的第二种方法是尝试绝对进口。如果我知道我的项目根文件夹在哪里,我可以将 .proto 文件移动到我希望 python 类所在的位置并在那里生成它们。对于此示例,我使用了与之前相同的文件夹结构,但没有./generated-folder。我还必须更改 protoc 命令的根文件夹,这需要我修改main_class.proto文件中的 import 语句,如下所示:

main_class.proto:

syntax = "proto3";

// Old
//import public "sub/sub_class.proto";
// New
import public "schemas/sub/sub_class.proto";

message MainClass {
    repeated SubClass subclass = 1;
}

协议命令

protoc -I=. --python_out=. schemas/main_class.proto schemas/sub/sub_class.proto

什么有效,什么无效

假设我的根文件夹也是我项目的根文件夹,这种方法现在让我可以在根文件夹中启动 python 并使用导入模块

import schemas.main_class_pb2

但是,这意味着我的 .proto 文件必须与该项目中的 python 文件位于相同的文件夹中,这看起来很混乱。这也意味着您必须从与项目相同的根文件夹中生成 python 文件,这并不总是可能的。.proto 文件可能用于为两个完全不同的应用程序创建一个通用接口,并且必须维护两个稍微不同的 protobuf 项目似乎违背了使用 protobuf 的目的。


示例 python 代码

我提供了一些示例 python 代码,可用于测试导入是否有效以及类是否按预期工作。此示例来自尝试 1,并假设从./generated文件夹启动 python

import main_class_pb2 as MC_proto

sub1, sub2 = (MC_proto.SubClass(name='sub1'),
              MC_proto.SubClass(name='sub2'))

sub1.log.append(MC_proto.LogMessage(status=1, timestamp='2020-01-01'))
sub1.log.append(MC_proto.LogMessage(status=0, timestamp='2020-01-01'))
sub2.log.append(MC_proto.LogMessage(status=1, timestamp='2020-01-02'))

main = MC_proto.MainClass(subclass=[sub1, sub2])
main
Out[]: 
subclass {
  name: "sub1"
  log {
    status: STATUS_OK
    timestamp: "2020-01-01"
  }
  log {
    timestamp: "2020-01-01"
  }
}
subclass {
  name: "sub2"
  log {
    status: STATUS_OK
    timestamp: "2020-01-02"
  }
}
4

0 回答 0