Protobuf是否支持Python的相对导入?
我一直在尝试创建一个支持此功能的protobuf构建脚本。从我的.proto文件生成python类时,只有在启动python程序的目录与生成的.py文件所在目录相同时,才能成功导入python模块。
我已经构建了以下最小可行方案。理想情况下,我希望生成的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 命令:
从根文件夹开始:
protoc -I=schemas --python_out=generated main_class.proto sub/sub_class.proto
这将把 python 文件放到 ./generated
文件夹中。
哪些可以使用,哪些不行
使用以上方法,我可以在文件夹 ./generated
中启动 python 并使用
import main_class_pb2 as MC_proto
导入。
然而,当我从 .
根文件夹(或任何其他文件夹)启动 python 时,使用
import generated.main_class_pb2 as MC_proto
会出现错误 ModuleNotFoundError: No module named 'sub'
。基于 此帖子,我手动修改了生成的 main_class_pb2.py
文件,如下所示:
# 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 *
通过在导入语句的开头添加 .
,我现在能够使用 import generated.main_class_pb2 as MC_proto
从根文件夹导入模块。但是,每次都手动编辑生成的文件非常不实用,所以我不喜欢这种方法。尝试2:绝对导入
我的第二个尝试是尝试绝对导入。如果我知道我的项目根文件夹在哪里,我就可以将.proto文件移动到想要Python类的位置并在那里生成它们。对于此示例,我使用与之前相同的文件夹结构,但没有
./generated
文件夹。我还必须更改protoc命令的根文件夹,并相应修改 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命令
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,并假定Python是从./generated
文件夹启动的。
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"
}
}
PYTHONPATH
中,它们所在的位置就不重要。PYTHONPATH
设置为什么? - Greg KrimerPYTHONPATH
。问题在于,在我的尝试1中(这是我最理想的方法),相对导入没有被 protoc 自动处理。有没有办法告诉 python-converter 我想要相对导入? - ViggoTW