Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ VERSION_FILES := Cargo.toml \
bindings/golang/Cargo.toml \
bindings/python/Cargo.toml \
bindings/python/pyproject.toml \
bindings/python/src/smg/version.py
bindings/python/src/smg/version.py \
grpc_client/python/pyproject.toml \
grpc_client/python/smg_grpc_proto/__init__.py

show-version: ## Show current version across all files
@echo "Current versions:"
Expand All @@ -148,6 +150,8 @@ show-version: ## Show current version across all files
@echo " bindings/python/Cargo.toml: $$(grep -m1 '^version = ' bindings/python/Cargo.toml | sed 's/version = "\(.*\)"/\1/')"
@echo " bindings/python/pyproject.toml: $$(grep -m1 '^version = ' bindings/python/pyproject.toml | sed 's/version = "\(.*\)"/\1/')"
@echo " bindings/python/.../version.py: $$(grep '__version__' bindings/python/src/smg/version.py | sed 's/__version__ = "\(.*\)"/\1/')"
@echo " grpc_client/python/pyproject.toml: $$(grep -m1 '^version = ' grpc_client/python/pyproject.toml | sed 's/version = "\(.*\)"/\1/')"
@echo " grpc_client/python/.../__init__.py: $$(grep '__version__' grpc_client/python/smg_grpc_proto/__init__.py | sed 's/__version__ = "\(.*\)"/\1/')"

bump-version: ## Bump version across all files (usage: make bump-version VERSION=0.3.3)
@if [ -z "$(VERSION)" ]; then \
Expand All @@ -169,12 +173,18 @@ bump-version: ## Bump version across all files (usage: make bump-version VERSION
@sed -i.bak 's/^version = ".*"/version = "$(VERSION)"/' bindings/python/pyproject.toml && rm -f bindings/python/pyproject.toml.bak
@# Update version.py
@sed -i.bak 's/__version__ = ".*"/__version__ = "$(VERSION)"/' bindings/python/src/smg/version.py && rm -f bindings/python/src/smg/version.py.bak
@# Update grpc_client/python/pyproject.toml
@sed -i.bak 's/^version = ".*"/version = "$(VERSION)"/' grpc_client/python/pyproject.toml && rm -f grpc_client/python/pyproject.toml.bak
@# Update grpc_client/python/smg_grpc_proto/__init__.py
@sed -i.bak 's/__version__ = ".*"/__version__ = "$(VERSION)"/' grpc_client/python/smg_grpc_proto/__init__.py && rm -f grpc_client/python/smg_grpc_proto/__init__.py.bak
@echo "Version updated to $(VERSION) in all files:"
@echo " - Cargo.toml"
@echo " - bindings/golang/Cargo.toml"
@echo " - bindings/python/Cargo.toml"
@echo " - bindings/python/pyproject.toml"
@echo " - bindings/python/src/smg/version.py"
@echo " - grpc_client/python/pyproject.toml"
@echo " - grpc_client/python/smg_grpc_proto/__init__.py"
@echo ""
@echo "Verify with: make show-version"

Expand Down
7 changes: 7 additions & 0 deletions grpc_client/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Generated stubs (created at build time)
smg_grpc_proto/generated/

# Build artifacts
dist/
*.egg-info/
build/
45 changes: 45 additions & 0 deletions grpc_client/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# smg-grpc-proto

Protocol Buffer definitions for SMG (Shepherd Model Gateway) gRPC services.

This package provides the Python gRPC stubs for:
- **SGLang** scheduler service
- **vLLM** engine service
- **TRT-LLM** service

## Installation

```bash
pip install smg-grpc-proto
```

## Usage

```python
from smg_grpc_proto import sglang_scheduler_pb2, sglang_scheduler_pb2_grpc
from smg_grpc_proto import vllm_engine_pb2, vllm_engine_pb2_grpc
from smg_grpc_proto import trtllm_service_pb2, trtllm_service_pb2_grpc
```

## Development

The proto files are located in `grpc_client/proto/` in the SMG repository. A symlink at `smg_grpc_proto/proto` points to the proto source files. Python stubs are generated at build time using `grpcio-tools`.

To install in editable mode:

```bash
# From repo root (symlink handles proto file discovery)
pip install -e grpc_client/python/
```

For CI or environments where symlinks don't work:

```bash
mkdir -p grpc_client/python/smg_grpc_proto/proto
cp grpc_client/proto/*.proto grpc_client/python/smg_grpc_proto/proto/
pip install -e grpc_client/python/
Comment thread
CatherineSue marked this conversation as resolved.
```

## License

Apache-2.0
40 changes: 40 additions & 0 deletions grpc_client/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[build-system]
requires = ["setuptools>=68.0", "grpcio-tools>=1.62.0"]
build-backend = "setuptools.build_meta"

[project]
name = "smg-grpc-proto"
version = "0.3.2"
description = "SMG gRPC proto definitions for SGLang, vLLM, and TRT-LLM"
requires-python = ">=3.10"
dependencies = [
"grpcio>=1.62.0",
"protobuf>=5.26.0",
]
readme = "README.md"
license = { text = "Apache-2.0" }
authors = [
{name = "Simo Lin", email = "linsimo.mark@gmail.com"},
{name = "Chang Su", email = "mckvtl@gmail.com"},
{name = "Keyang Ru", email = "rukeyang@gmail.com"}
]
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
]

[project.urls]
Homepage = "https://github.com/lightseekorg/smg"
Repository = "https://github.com/lightseekorg/smg"

[tool.setuptools.packages.find]
where = ["."]
include = ["smg_grpc_proto*"]

[tool.setuptools.package-data]
smg_grpc_proto = ["proto/*.proto", "generated/*.py", "generated/*.pyi"]
103 changes: 103 additions & 0 deletions grpc_client/python/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""
Custom setup.py to generate protobuf stubs at build time.
The generated files are NOT committed to git — they're created fresh during pip install.
"""
from pathlib import Path

from setuptools import setup
from setuptools.command.build_py import build_py
from setuptools.command.develop import develop


def compile_grpc_protos():
"""Generate Python gRPC stubs from .proto files."""
package_dir = Path(__file__).parent
proto_dir = package_dir / "smg_grpc_proto" / "proto"
output_dir = package_dir / "smg_grpc_proto" / "generated"

output_dir.mkdir(parents=True, exist_ok=True)
(output_dir / "__init__.py").write_text(
'"""Auto-generated protobuf stubs. Do not edit."""\n'
)

proto_files = list(proto_dir.glob("*.proto"))
if not proto_files:
raise FileNotFoundError(f"No .proto files found in {proto_dir}")

# Use grpc_tools.protoc Python API (same approach as vLLM)
try:
from grpc_tools import protoc

args = [
"grpc_tools.protoc",
f"--proto_path={proto_dir}",
f"--python_out={output_dir}",
f"--grpc_python_out={output_dir}",
f"--pyi_out={output_dir}", # Generate type stubs
] + [str(f) for f in proto_files]

print(f"Generating protobuf stubs from {len(proto_files)} proto files...")
result = protoc.main(args)

if result != 0:
raise RuntimeError(f"protoc returned non-zero exit code: {result}")

except ImportError:
raise RuntimeError(
"grpcio-tools not installed. Install with: pip install grpcio-tools"
)

# Fix imports in generated files (grpcio-tools generates absolute imports)
# Also add mypy ignore-errors comment for generated code
mypy_header = "# mypy: ignore-errors\n"

for py_file in output_dir.glob("*_pb2*.py"):
content = py_file.read_text()

# Fix imports to be relative
for proto_file in proto_files:
module_name = proto_file.stem + "_pb2"
content = content.replace(
f"import {module_name}", f"from . import {module_name}"
)

# Add mypy ignore-errors if not already present
if not content.startswith("# mypy:"):
content = mypy_header + content

py_file.write_text(content)

# Also add mypy header to .pyi files
for pyi_file in output_dir.glob("*_pb2*.pyi"):
content = pyi_file.read_text()
if not content.startswith("# mypy:"):
pyi_file.write_text(mypy_header + content)

generated_count = len(list(output_dir.glob("*.py"))) + len(
list(output_dir.glob("*.pyi"))
)
print(f"Generated {generated_count} files (including type stubs)")


class BuildPyWithProto(build_py):
"""Custom build_py that generates protobuf stubs before building."""

def run(self):
compile_grpc_protos()
super().run()


class DevelopWithProto(develop):
"""Custom develop that generates protobuf stubs for editable installs."""

def run(self):
compile_grpc_protos()
super().run()


setup(
cmdclass={
"build_py": BuildPyWithProto,
"develop": DevelopWithProto,
}
)
27 changes: 27 additions & 0 deletions grpc_client/python/smg_grpc_proto/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""SMG gRPC Proto - Protocol definitions for SGLang, vLLM, and TRT-LLM."""

__version__ = "0.3.2"

# Re-export generated modules for convenient access
# These imports will work after the package is built (stubs generated at build time)
try:
from smg_grpc_proto.generated import (
sglang_scheduler_pb2,
sglang_scheduler_pb2_grpc,
trtllm_service_pb2,
trtllm_service_pb2_grpc,
vllm_engine_pb2,
vllm_engine_pb2_grpc,
)

__all__ = [
"sglang_scheduler_pb2",
"sglang_scheduler_pb2_grpc",
"vllm_engine_pb2",
"vllm_engine_pb2_grpc",
"trtllm_service_pb2",
"trtllm_service_pb2_grpc",
]
except ImportError:
# During development/build, generated modules may not exist yet
__all__ = []
1 change: 1 addition & 0 deletions grpc_client/python/smg_grpc_proto/proto