Skip to content

Python Language Support

Status: ✅ Full Support
Example: examples/python-example/

Python support provides comprehensive Protocol Buffer integration with multiple output options including gRPC, type stubs, and modern dataclass alternatives.

PluginDescriptionGenerated Files
protoc-gen-pythonBase message generation*_pb2.py
protoc-gen-grpc_pythongRPC services*_pb2_grpc.py
protoc-gen-pyiType stubs for IDE support*_pb2.pyi
protoc-gen-mypyMypy type checking stubs*_pb2.pyi, *_pb2_grpc.pyi
protoc-gen-python_betterprotoModern dataclass approach*.py (with @dataclass)
protoc-gen-python_betterproto (with pydantic)Validated dataclasses*.py (with Pydantic validation)
languages.python = {
enable = true;
outputPath = "proto/gen/python";
};
languages.python = {
enable = true;
outputPath = "proto/gen/python";
options = [];
# gRPC service generation
grpc = {
enable = true;
options = [];
};
# Type stubs for better IDE support
pyi = {
enable = true;
options = [];
};
# Mypy type checking support
mypy = {
enable = true;
options = [];
};
# Modern Python dataclasses (alternative to standard protobuf)
betterproto = {
enable = false; # Opt-in due to different API
pydantic = false; # Enable Pydantic dataclasses for validation
options = [];
};
};
🆕 New Feature

Control exactly which proto files Python processes using files and additionalFiles:

Use Case: Python needs data processing and ML proto files.

languages.python = {
enable = true;
outputPath = "ml_backend/proto";
# Override: Only data science and ML-related protos
files = [
"./proto/common/v1/types.proto"
"./proto/ml/v1/training_service.proto"
"./proto/ml/v1/inference_service.proto"
"./proto/data/v1/pipeline_service.proto"
"./proto/analytics/v1/metrics.proto"
# No frontend APIs - backend data processing only
];
grpc.enable = true;
mypy.enable = true;
};
OptionTypeDescriptionExample
fileslistOverride global files completelyMicroservice-specific APIs
additionalFileslistExtend global filesAdd Google Cloud protos

Data Science

Include ML training and inference service definitions

Cloud Integration

Add Google Cloud or AWS service proto definitions

Microservice Focus

Process only relevant service definitions per microservice

Third-Party APIs

Include external protobuf dependencies and frameworks

proto/example/v1/example.proto
syntax = "proto3";
package example.v1;
message Greeting {
string id = 1;
string content = 2;
int64 created_at = 3;
repeated string tags = 4;
map<string, string> metadata = 5;
oneof optional_field {
string text_value = 6;
int32 numeric_value = 7;
}
}
enum GreetingType {
GREETING_TYPE_UNSPECIFIED = 0;
GREETING_TYPE_HELLO = 1;
GREETING_TYPE_GOODBYE = 2;
GREETING_TYPE_WELCOME = 3;
}
message CreateGreetingRequest {
string content = 1;
repeated string tags = 2;
GreetingType type = 3;
}
message CreateGreetingResponse {
Greeting greeting = 1;
}
message ListGreetingsRequest {
int32 page_size = 1;
string page_token = 2;
GreetingType type_filter = 3;
}
message ListGreetingsResponse {
repeated Greeting greetings = 1;
string next_page_token = 2;
}
service GreetingService {
rpc CreateGreeting(CreateGreetingRequest) returns (CreateGreetingResponse);
rpc ListGreetings(ListGreetingsRequest) returns (ListGreetingsResponse);
rpc StreamGreetings(ListGreetingsRequest) returns (stream Greeting);
rpc BidirectionalStream(stream CreateGreetingRequest) returns (stream Greeting);
}
import grpc
from proto.gen.python.example.v1 import example_pb2
from proto.gen.python.example.v1 import example_pb2_grpc
# Client usage
async def main():
# Create channel and stub
channel = grpc.insecure_channel('localhost:50051')
stub = example_pb2_grpc.GreetingServiceStub(channel)
# Create a greeting
request = example_pb2.CreateGreetingRequest(
content="Hello from Python!",
tags=["python", "grpc", "example"],
type=example_pb2.GREETING_TYPE_HELLO
)
response = stub.CreateGreeting(request)
print(f"Created greeting: {response.greeting.id}")
# Work with the message
greeting = response.greeting
print(f"Content: {greeting.content}")
print(f"Tags: {list(greeting.tags)}")
# Access map fields
greeting.metadata["author"] = "Python Client"
greeting.metadata["version"] = "1.0"
# Serialize to bytes
data = greeting.SerializeToString()
print(f"Serialized size: {len(data)} bytes")
# Deserialize from bytes
new_greeting = example_pb2.Greeting()
new_greeting.ParseFromString(data)
# JSON support
from google.protobuf.json_format import MessageToJson, Parse
json_str = MessageToJson(greeting)
print(f"JSON: {json_str}")
# Parse from JSON
from_json = Parse(json_str, example_pb2.Greeting())
import pytest
from proto.gen.python.example.v1 import example_pb2
def test_greeting_creation():
"""Test creating and serializing a greeting"""
greeting = example_pb2.Greeting(
id="test-1",
content="Test greeting",
created_at=1234567890
)
greeting.tags.extend(["test", "unit"])
greeting.metadata["test"] = "true"
# Test serialization
data = greeting.SerializeToString()
assert len(data) > 0
# Test deserialization
new_greeting = example_pb2.Greeting()
new_greeting.ParseFromString(data)
assert new_greeting.id == "test-1"
assert new_greeting.content == "Test greeting"
assert list(new_greeting.tags) == ["test", "unit"]
assert dict(new_greeting.metadata) == {"test": "true"}
@pytest.mark.asyncio
async def test_grpc_service():
"""Test gRPC service calls"""
# Mock or integration test your service
pass
  1. Use Type Stubs: Enable pyi or mypy for better IDE support
  2. Async Support: Use grpc.aio for async/await support
  3. Error Handling: Always handle grpc.RpcError exceptions
  4. Streaming: Use generators efficiently for streaming RPCs
  5. Betterproto: Consider for new projects wanting modern Python APIs
  6. Pydantic Validation: Enable betterproto.pydantic = true for data validation
  7. Package Structure: Follow Python package conventions
  8. Validation Strategy: Use proto field constraints for comprehensive validation
  • Directoryproto/ - gen/ - python/ - example/ - v1/ - __init__.py - example_pb2.py
  • example_pb2.pyi If pyi/mypy enabled - example_pb2_grpc.py - example_pb2_grpc.pyi If pyi/mypy enabled
  • Standard protobuf: Best performance, C++ implementation
  • Betterproto: Pure Python, slower but cleaner API
  • Betterproto + Pydantic: Additional validation overhead, enhanced safety
  • Serialization: Binary format is much smaller than JSON
  • Streaming: More efficient for large datasets
  • Validation: Pydantic validation has runtime cost but prevents data errors
Terminal window
# Standard Python example
cd examples/python-example
nix develop
bufrnix_init
bufrnix
python main.py
pytest -v
# Betterproto with Pydantic validation
cd examples/python-betterproto-pydantic
nix develop
nix run # Generate code
python test_pydantic.py # Test validation features

Ensure the generated code directory is in your Python path:

import sys
sys.path.append('./proto/gen/python')

For mypy to work correctly, use:

Terminal window
mypy --follow-imports=skip proto/gen/python/

Betterproto generates different code than standard protobuf. Don’t mix them in the same project.

For comprehensive validation with Pydantic:

  1. Define field constraints in your .proto files
  2. Use proto validation annotations (e.g., buf validate)
  3. Handle ValidationError exceptions in your code
  4. Consider validation performance impact for high-throughput scenarios
{
  description = "Python with betterproto example";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    bufrnix = {
      url = "github:conneroisu/bufrnix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = {
    self,
    nixpkgs,
    flake-utils,
    bufrnix,
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};

      bufrnixConfig = bufrnix.lib.mkBufrnix {
        inherit pkgs;
        config = {
          root = "./proto";

          # Python with betterproto for modern dataclasses
          languages.python = {
            enable = true;
            outputPath = "proto/gen/python";

            # Per-language file control (new feature)
            # files = [
            #   "./proto/common/v1/types.proto"
            #   "./proto/ml/v1/training_service.proto"
            # ];
            # additionalFiles = [
            #   "./proto/google/cloud/storage/v1/storage.proto"
            #   "./proto/third_party/tensorflow/serving/apis/model.proto"
            # ];

            # Use betterproto instead of standard protobuf
            betterproto = {
              enable = true;
            };
          };
        };
      };
    in {
      devShells.default = pkgs.mkShell {
        buildInputs = with pkgs; [
          python3
          python3Packages.betterproto
          python3Packages.grpclib # betterproto uses grpclib instead of grpcio
          protobuf
        ];

        shellHook = ''
          echo "Python Betterproto Example"
          echo "========================="
          echo "Commands:"
          echo "  bufrnix_init - Initialize project"
          echo "  bufrnix - Generate betterproto code"
          echo "  python test_betterproto.py - Run test"
          echo ""
          echo "Note: Betterproto generates modern Python dataclasses"
          echo "      with async support and cleaner API"
          echo ""
          ${bufrnixConfig.shellHook}
        '';
      };
    });
}