python3 grpc 编译器:如何处理 .protos 中的绝对和相对导入?

python3 grpc compiler: how to handle absolute and relative imports in .protos?

我正在尝试从 containerd API .proto 文件生成工作 Python 模块,可在此处找到:https://github.com/containerd/containerd/tree/master/api.

不幸的是,containerd 自己的 .proto 文件包含诸如(在 api/events/container.proto 中)的引用:

import weak "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto";

现在,这个导入实际上位于 protobuf/plugin/fieldpath.proto,而不是 (vendor/)github.com/containerd/...。简单的 -I ... 在此上下文中不起作用,因为导入使用“github”-绝对路径,而相应的源不在供应商分支内。

在尝试使用生成的 Python 模块时,简单地复制 vendor/github.com/... 内的源将导致运行时错误:这是因为现在有两个单独的实例用于尝试注册相同的协议元素与具有相同协议元素名称的 GRPC,但来自两个不同的 Python 模块。 GRPC Python 运行时因此抛出错误并终止。

使用 python3 -m grpc.tools.protoc ... 时如何正确解决此问题?

经过反复试验,我终于想出了一个工作解决方案,其工作原理如下,这可能对其他面临基于 gRPC API 的人有帮助,这些问题比许多 gRPC 示例更复杂。

  1. 将 API .proto 文件复制到反映最终所需 Python 包和模块结构的目录结构中。对于 containerd,这意味着将所有内容都放在 containerd/ 目录结构中,避免 github.com/ 文件夹和别名(导入别名会破坏内容)。
  2. 修复所有会导致模块别名或不适合最终所需包结构的导入语句路径。执行此操作的一个好方法是在复制原型文件时使用 sed。在我的例子中,将“github.com/containerd/containerd/...”替换为“containerd/...”导入路径。
  3. 如果供应商提供的 .proto 文件以某种方式与 gRPC 基础设施相关并且存在 gRPC PyPI 包,例如 grpcio 和 protobuf,请将其与您的 API .proto 文件并排放置,但不要将它们出售到 API 目录层次结构中。确保将它们放在模仿现有 PyPI 包的包结构的目录结构中。
  4. 通过 python3 解释器使用 protoc 为您的 API .proto 文件生成 Python 模块;确保来自 grpc 和 protobuf 的补充 .proto 文件是可包含的,但不要为它们创建模块。 protoc 已经正确地做到了这一点,除非你将补充的 .proto 文件提供给你的 API .proto 文件......所以不要这样做。
  5. 确保你的 grpcio 和 protobuf PyPI 包是最新的并且以某种方式同步,特别是避免完全过时的 Debian 发行版包,从 PyPI 安装......即使这在 arm64 上是一个痛苦的缓慢过程,因为没有二进制文件grpcio 和 grpciotools 的轮子。不这样做的症状包括缺少 grpc 或 protobuf 对象字段的运行时错误。