[grpc] Fix protobuf compilation in isolated build environments (#16754)
This commit is contained in:
@@ -6,8 +6,7 @@ to automatically generate gRPC/protobuf Python files from .proto sources
|
||||
when building the wheel or doing editable installs.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from setuptools import setup
|
||||
@@ -32,31 +31,44 @@ def compile_proto():
|
||||
output_dir = proto_path.parent
|
||||
proto_dir = proto_path.parent
|
||||
|
||||
# Build the protoc command
|
||||
cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"grpc_tools.protoc",
|
||||
# Import grpc_tools.protoc directly instead of running as subprocess.
|
||||
# This ensures we use the grpcio-tools installed in the build environment,
|
||||
# since sys.executable may point to the main Python interpreter in
|
||||
# pip's isolated build environments.
|
||||
try:
|
||||
import grpc_tools
|
||||
from grpc_tools import protoc
|
||||
except ImportError as e:
|
||||
raise SetupError(
|
||||
f"Failed to import grpc_tools: {e}. "
|
||||
"Ensure grpcio-tools is listed in build-system.requires in pyproject.toml"
|
||||
)
|
||||
|
||||
# Get the path to well-known proto files bundled with grpcio-tools
|
||||
# (e.g., google/protobuf/timestamp.proto, google/protobuf/struct.proto)
|
||||
grpc_tools_proto_path = Path(grpc_tools.__file__).parent / "_proto"
|
||||
|
||||
# Build the protoc arguments (protoc.main expects argv-style list)
|
||||
args = [
|
||||
"protoc", # argv[0] is the program name
|
||||
f"-I{proto_dir}",
|
||||
f"-I{grpc_tools_proto_path}", # Include path for well-known protos
|
||||
f"--python_out={output_dir}",
|
||||
f"--grpc_python_out={output_dir}",
|
||||
f"--pyi_out={output_dir}",
|
||||
proto_path.name,
|
||||
str(proto_dir / proto_path.name),
|
||||
]
|
||||
|
||||
print(f"Running: {' '.join(cmd)}")
|
||||
print(f"Running protoc with args: {args[1:]}")
|
||||
|
||||
# Save and restore cwd since protoc may change it
|
||||
original_cwd = os.getcwd()
|
||||
try:
|
||||
subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=proto_dir,
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_msg = e.stderr or e.stdout or "Unknown error"
|
||||
raise SetupError(f"protoc failed with exit code {e.returncode}: {error_msg}")
|
||||
result = protoc.main(args)
|
||||
if result != 0:
|
||||
raise SetupError(f"protoc failed with exit code {result}")
|
||||
finally:
|
||||
os.chdir(original_cwd)
|
||||
|
||||
# Fix imports in generated grpc file (change absolute to relative imports)
|
||||
_fix_imports(output_dir, proto_path.stem)
|
||||
|
||||
Reference in New Issue
Block a user