[Python] bazel build and run grpc server with python

Discussão em 'Python' iniciado por Stack, Março 3, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to setup a larger bazel infrastructure to

    1. Create .py files from a .proto file for gRPC using rules_proto_grpc_python
    2. Run the server code that implements the interfaces defined in 1 via a py_binary

    However, I am getting the error

    google.protobuf.runtime_version.VersionError: Detected incompatible Protobuf Gencode/Runtime versions
    when loading helloworld/hello.proto: gencode 5.29.1 runtime 5.27.2. Runtime version
    cannot be older than the linked gencode version. See Protobuf version
    guarantees at https://protobuf.dev/support/cross-version-runtime-guarantee.


    indicating that the protobuf version that rules_proto_grpc_python uses to generate the .py files is different from the version used at runtime. I tried to require protobuf>=5.29.1 for the `py_binary`` but that is not possible due to conficts with other packages in the project. In this minimal example, it is possible but issues several warnings about conflicting symlinks which seems concerning as well. Is there a way to either

    1. Specify the protobuf version to use for rules_proto_grpc_python
    2. Generate the .py files from the .proto in another way?
    Edit 2025-02-27


    I managed to get this to work by playing around with the requirements in my larger repository. Specifying the minimum protobuf version causes it to work.

    Here are the relevant files to make a minimal example


    The top-level MODULE.bazel:

    # MODULE.bazel

    bazel_dep(name = "aspect_bazel_lib", version = "2.7.8")
    bazel_dep(name = "aspect_rules_py", version = "1.3.2")
    bazel_dep(name = "rules_python", version = "1.1.0")
    bazel_dep(name = "rules_proto", version = "7.1.0")
    bazel_dep(name = "rules_proto_grpc_python", version = "5.0.0")


    # deps for python projects.
    _PY_MINOR_VER = 10

    _PY_VERSION = "3.%s" % _PY_MINOR_VER

    _PY_VER_ = "python_3_%s" % _PY_MINOR_VER

    python = use_extension("@rules_python//python/extensions:python.bzl", "python")
    python.toolchain(
    python_version = _PY_VERSION,
    is_default = True,
    )

    # You can use this repo mapping to ensure that your BUILD.bazel files don't need
    # to be updated when the python version changes to a different `3.12` version.
    use_repo(
    python,
    "python_3_%s" % _PY_MINOR_VER,
    )

    pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
    pip.parse(
    hub_name = "pypi",
    # We need to use the same version here as in the `python.toolchain` call.
    python_version = _PY_VERSION,
    requirements_lock = "//:requirements_lock.txt",
    )
    use_repo(pip, "pypi")


    Inside a directory /proto_library/proto/hello.proto

    # proto_library/proto/hello.proto

    syntax = "proto3";

    package helloworld;

    // The greeting service definition.
    service Greeter {
    // Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {}
    }

    // The request message containing the user's name.
    message HelloRequest {
    string name = 1;
    }

    // The response message containing the greetings
    message HelloReply {
    string message = 1;
    }


    The BUILD.bazel alongside the proto file

    # proto_library/proto/BUILD.bazel

    load("@rules_proto//proto:defs.bzl", "proto_library")
    load("@rules_proto_grpc_python//:defs.bzl", "py_proto_library", "py_grpc_library")


    proto_library(
    name = "hello_proto",
    srcs = ["hello.proto"],
    # Add these to control Python package structure
    strip_import_prefix = "/proto_library/proto",
    import_prefix = "helloworld",
    visibility = ["//visibility:public"],
    )

    py_proto_library(
    name = "hello_py_proto",
    protos = [":hello_proto"],
    visibility = ["//visibility:public"],
    )

    py_grpc_library(
    name = "hello_py_grpc",
    protos = [":hello_proto"],
    visibility = ["//visibility:public"],
    deps = [":hello_py_proto"],
    )


    The python code to implement the server

    # proto_library/src/hello_server.py

    import logging
    import sys
    from concurrent import futures

    import grpc
    from helloworld import hello_pb2, hello_pb2_grpc


    class Greeter(hello_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
    return hello_pb2.HelloReply(message="Hello, %s!" % request.name)


    def serve():
    port = "50051"
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port("[::]:" + port)
    server.start()
    print("Server started, listening on " + port)
    server.wait_for_termination()


    if __name__ == "__main__":
    logging.basicConfig()
    serve()



    And finally, the BUILD file inside proto_library

    # proto_library/BUILD.bazel

    load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library")
    load("@pypi//:requirements.bzl", "requirement")


    py_binary(
    name = "hello_test",
    srcs = ["src/hello_server.py"],
    deps = [
    "//proto_library/proto:hello_py_proto",
    "//proto_library/proto:hello_py_grpc",
    requirement("grpcio"),
    requirement("protobuf"),
    ],
    # Add these to handle Python packaging
    imports = [".."], # Make parent directories importable
    visibility = ["//visibility:public"],
    package_collisions = "warning",
    # Create proper Python package structure
    main = "hello_server.py",
    )

    Continue reading...

Compartilhe esta Página