Betterproto: A Protobuf & gRPC Library for Python
Betterproto is a Python library that generates Python dataclasses, Protobuf serialization, and gRPC client/server stubs directly from `.proto` files. It aims to provide a more Pythonic interface than the official `protobuf` library. The current stable version is 1.2.5, but a 2.0.0 beta is under active development, introducing significant breaking changes and new features. Releases are somewhat irregular, with recent focus on the 2.0.0 branch.
Warnings
- breaking Betterproto v2.0.0b7+ drops support for Pydantic v1. If you use Pydantic dataclasses, you must upgrade to Pydantic v2.
- breaking In Betterproto v2.0.0b7+, attempting to access an unset `oneof` field will now raise an `AttributeError`. Previously, this might have returned a default value or `None` without explicit checking.
- breaking Betterproto v2.0.0b6+ requires Python 3.7 or newer. Earlier beta versions had different minimum Python requirements.
- breaking In Betterproto v2.0.0b5+, gRPC client calls and server handlers now require input message fields to be explicitly wrapped in their respective message objects.
- gotcha Betterproto is a code generator; you *must* have the `protoc` (Protocol Buffers compiler) executable installed and in your system's PATH to use it. `pip install betterproto` only installs the Python library and its `protoc` plugin, not `protoc` itself.
- gotcha The `betterproto` library has two major versions currently active: stable `1.x` and an actively developed `2.x` beta. The `2.x` branch introduces many breaking changes and new features (like Pydantic v2 support, gRPC API changes, etc.).
Install
-
pip install betterproto -
pip install betterproto==2.0.0b7
Imports
- Message
from betterproto import Message
- enum
import betterproto.enum
- string_field
from betterproto import string_field
Quickstart
import os
from pathlib import Path
import subprocess
import sys
# 1. Define a .proto file
proto_content = """
syntax = "proto3";
message GreetRequest {
string name = 1;
}
message GreetResponse {
string greeting = 1;
}
"""
proto_file_path = Path("greet.proto")
proto_file_path.write_text(proto_content)
# 2. Compile the .proto file using protoc with betterproto plugin
# Ensure `protoc` is installed and in your PATH.
# The betterproto Python package ships its own protoc plugin.
try:
# Find the betterproto plugin
betterproto_plugin = next(
p for p in sys.path if 'betterproto' in p and 'site-packages' in p
) + '/betterproto/plugin/protoc-gen-python_betterproto'
print(f"Using betterproto plugin: {betterproto_plugin}")
compile_command = [
"protoc",
f"--plugin=protoc-gen-python_betterproto={betterproto_plugin}",
"--python_betterproto_out=.",
str(proto_file_path)
]
subprocess.run(compile_command, check=True, capture_output=True)
print("Proto file compiled successfully to greet.py")
# 3. Use the generated Python code
from greet import GreetRequest, GreetResponse
request = GreetRequest(name="World")
print(f"Created request: {request.name}")
# Serialize the message
serialized_data = bytes(request)
print(f"Serialized data (bytes): {serialized_data}")
# Deserialize the message
deserialized_request = GreetRequest().parse(serialized_data)
print(f"Deserialized request: {deserialized_request.name}")
response = GreetResponse(greeting=f"Hello, {deserialized_request.name}!")
print(f"Created response: {response.greeting}")
except FileNotFoundError:
print("Error: 'protoc' command not found. Please install Protocol Buffers compiler.")
except subprocess.CalledProcessError as e:
print(f"Error compiling proto file: {e.stderr.decode()}")
except ImportError:
print("Error: Could not import generated 'greet' module. Compilation might have failed or plugin path is incorrect.")
finally:
# Clean up generated files
Path("greet.py").unlink(missing_ok=True)
Path("greet.proto").unlink(missing_ok=True)
print("Cleaned up temporary files.")