I have my .proto
. files defined in a folder workspace_directory/sub_directory/proto_files
.
When I run:
protoc --python_out=workspace_directory -I workspace_directory/sub_directory/proto_files workspace_directory/sub_directory/proto_files/*
the output python code is generated in workspace_directory/proto_files
, which is what I want.
My main goal is to run that command as part of a build script in Python, so I attempted to use subprocess.run()
to achieve that. In Python I run:
subprocess.run(shlex.split("protoc --python_out=workspace_directory -I workspace_directory/sub_directory/proto_files workspace_directory/sub_directory/proto_files/*"))
I get
Could not make proto path relative: workspace_directory/sub_directory/proto_files/*: No such file or directory
Some other things to note:
workspace_directory
is a fully qualified path. Its like /home/user/workspace_directory
, so I don't believe I should be having any relative path problems.shlex.split()
so I could copy/paste the command, to ensure it was as exact as possible.It feels like I'm missing something when using the subprocess
module, but can't seem to see it.
protoc --python_out=workspace_directory -I workspace_directory/sub_directory/proto_files workspace_directory/sub_directory/proto_files/*
When you execute this command normally in bash
or other shell, the shell detects the *
wildcard character and converts it to a list of matching filenames.
Neither subprocess.run()
nor shlex.split()
do any wildcard handling, so protoc
receives the text as-is and tries to open a file literally called *
, which it cannot find. The error message is a bit confusing, but contains the reason: No such file or directory
.
Calling the command through the shell is a reasonable solution as long as you can trust all the text strings you include in the command. Alternatively you can use the Python glob
module to expand the wildcard to a list of paths and include it in the command. That can be safer if the filenames may contain special characters.
(You may also be interested in knowing that protoc
is available as a Python module in grpcio-tools
and can be called using import grpc_tools.protoc; grpc_tools.protoc.main(['protoc', '-I...', 'myproto.proto'])
. This avoids having to go through a subprocess, and can be easier to install using the Python pip
package manager.)