我有我的
.proto
。文件夹中定义的文件 workspace_directory/sub_directory/proto_files
.
当我跑步时:
protoc --python_out=workspace_directory -I workspace_directory/sub_directory/proto_files workspace_directory/sub_directory/proto_files/*
输出的python代码在
workspace_directory/proto_files
中生成,这就是我想要的。
我的主要目标是将该命令作为 Python 构建脚本的一部分运行,因此我尝试使用
subprocess.run()
来实现这一目标。在Python中我运行:
subprocess.run(shlex.split("protoc --python_out=workspace_directory -I workspace_directory/sub_directory/proto_files workspace_directory/sub_directory/proto_files/*"))
我明白了
无法使原始路径相对:workspace_directory/sub_directory/proto_files/*:没有这样的文件或目录
其他一些注意事项:
workspace_directory
是完全合格的路径。它就像 /home/user/workspace_directory
,所以我认为我不应该遇到任何相对路径问题。shlex.split()
,这样我就可以复制/粘贴命令,以确保它尽可能准确。使用
subprocess
模块时感觉好像错过了一些东西,但又好像看不到它。
protoc --python_out=workspace_directory -I 工作空间目录/子目录/proto_files 工作空间目录/子目录/proto_files/*
当您在
bash
或其他 shell 中正常执行此命令时,shell 会检测到 *
通配符并将其转换为匹配文件名列表。
subprocess.run()
和 shlex.split()
都不进行任何通配符处理,因此 protoc
按原样接收文本并尝试打开一个字面上名为 *
的文件,但它无法找到该文件。错误消息有点混乱,但包含原因:No such file or directory
。
只要您可以信任命令中包含的所有文本字符串,通过 shell 调用命令就是一个合理的解决方案。或者,您可以使用 Python
glob
模块将通配符扩展为路径列表并将其包含在命令中。如果文件名可能包含特殊字符,那就更安全了。
(您可能还想知道
protoc
可以作为 grpcio-tools
中的 Python 模块使用,并且可以使用 import grpc_tools.protoc; grpc_tools.protoc(['protoc', '-I...', 'myproto.proto'])
进行调用。这避免了必须经过子进程,并且可以更轻松地使用 Python 安装pip
包管理器。)
我找到了解决方案。我仍然不确定为什么传递参数序列和使用带有
shell=True
的字符串之间存在差异
args 对于所有调用都是必需的,并且应该是字符串或程序参数序列。通常首选提供参数序列,因为它允许模块处理任何所需的参数转义和引用(例如,允许文件名中包含空格)。如果传递单个字符串,则 shell 必须为 True(见下文),否则该字符串必须简单地命名要执行的程序而不指定任何参数。
我一直在提供参数的顺序,但没有得到我想要的结果。传递一个字符串并设置
shell=True
使其工作。
subprocess.run("protoc --python_out=workspace_directory -I workspace_directory/sub_directory/proto_files workspace_directory/sub_directory/proto_files/*", shell=True)
尝试使用 Popen 命令。
import subprocess
cwd = os.getcwd() # Path where protobuf file is located
subprocess.Popen(["protoc", "-I", cwd, "--python_out", cwd, "your_file.proto"])
当应用程序必须导入模块时,我使用它来部署应用程序,如果不能,我使用 try catch 来执行上面的代码部分。