pythonprotocol-buffersgrpc

grpc_tools.protoc compiling grpc with edition = 2023 fails


I'm using protoc version 28.3 on macos:

> protoc --version
libprotoc 28.3

This version can generate gRPC for typescript and go and C++, with the appropriate plugins. It can also generate plain protobuf:

> protoc --experimental_editions -I src/proto3 --python_out=./src/generated/python/revepb src/proto3/*.proto
>

However, when I try to generate grpc, it fails:

> uv run python3 -m grpc_tools.protoc --experimental_editions -I src/proto3 --python_out=./src/generated/python/revepb src/proto3/*.proto
basetypes.generated.proto: is an editions file, but code generator --python_out hasn't been updated to support editions yet.  Please ask the owner of this code generator to add support or switch back to proto2/proto3.

This makes no sense because --python_out works well in isolation.

The closest I can think of would be that grpc_tools might include its own flavor of protoc, AND that tool hasn't been updated for two years or something.

These are the versions:

+ grpcio==1.67.1
+ grpcio-tools==1.67.1
+ protobuf==5.28.3
+ setuptools==75.5.0

1.67.1 is the latest released version, from October 28 2024.

What else can I check, version-wise?

I assume, perhaps wrongly, that "use grpc with editions in python" is a mainstream thing that I should expect to work, given that python is a core language inside google -- is this assumption wrong?

What else can I do to make this work?


Solution

  • I'm unable to repro your issue (on Linux), I tried:

    Yes, grpc_tools bundles a (current) protoc binary:

    python3 -m grpc_tools.protoc --version
    libprotoc 27.2
    

    You're missing the --grpc_python_out directive to generate service and rpc bindings:

    # Includes:
    # 1. `--pyi_out` for Python type-checking (not gRPC :-()
    # 2. `--grpc_python_out` for Python gRPC service|rpc stubs
    python3 \
    -m grpc_tools.protoc \
    --experimental_editions \
    --proto_path=${PWD} \
    --python_out=${PWD} \
    --pyi_out=${PWD} \
    --grpc_python_out=${PWD} \
    ${PWD}/foo.proto 
    

    And, using a gRPC-enabled variant of Player:

    foo.proto:

    // Edition version of proto2 file
    edition = "2023";
    
    package com.example;
    
    message Player {
      // fields have explicit presence, so no explicit setting needed
      string name = 1;
      // to match the proto2 behavior, LEGACY_REQUIRED is set at the field level
      int32 id = 2 [features.field_presence = LEGACY_REQUIRED];
      // to match the proto2 behavior, EXPANDED is set at the field level
      repeated int32 scores = 3 [features.repeated_field_encoding = EXPANDED];
    
      enum Handed {
        // this overrides the default edition 2023 behavior, which is OPEN
        option features.enum_type = CLOSED;
        HANDED_UNSPECIFIED = 0;
        HANDED_LEFT = 1;
        HANDED_RIGHT = 2;
        HANDED_AMBIDEXTROUS = 3;
      }
    
      Handed handed = 4;
    
      reserved gender;
    }
    
    // Some gRPC service
    service Foo {
      // Some gRPC method
      rpc Fooey (Player) returns (Player) {}
    }
    

    Yields:

    .
    ├── foo_pb2_grpc.py
    ├── foo_pb2.py
    ├── foo_pb2.pyi
    └── foo.proto
    

    From:

    python3 -m venv venv && \
    source venv/bin/activate && \
    python3 -m pip install grpcio && \
    python3 -m pip install grpcio-tools && \
    python3 -m pip freeze
    
    grpcio==1.67.1
    grpcio-tools==1.67.1
    protobuf==5.28.3