[grpc] Fix protobuf compilation in isolated build environments (#16754)

This commit is contained in:
Simo Lin
2026-01-08 13:09:01 -08:00
committed by GitHub
parent cf24232100
commit 55a8dd0095
4 changed files with 34 additions and 22 deletions

View File

@@ -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)