Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generated Python gRPC code cannot be imported when the path has dot #309

Open
linzhp opened this issue Jan 17, 2024 · 5 comments
Open

generated Python gRPC code cannot be imported when the path has dot #309

linzhp opened this issue Jan 17, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@linzhp
Copy link
Contributor

linzhp commented Jan 17, 2024

Issue Description

The the path of proto files has dot (e.g., k8s.io/apimachinery/pkg/runtime/generated.proto), the Python modules generated by python_grpc_library cannot be imported

Log Output

  bazel-bin/k8s.io/apimachinary/py_lib_pb/k8s/io/apimachinary/demo_pb2.py
  bazel-bin/k8s.io/apimachinary/py_lib_pb/k8s.io/apimachinary/demo_pb2_grpc.py

Notice the k8s/io vs k8s.io in the paths. The former can be imported, the latter cannot.

rules_proto_grpc Version

5.0.0-alpha3

Bazel Version

7.0.0

OS

Linux

Link to Demo Repo

No response

MODULE.bazel or WORKSPACE Content

module(name="k8s_test")

bazel_dep(name="rules_python", version="0.28.0")
bazel_dep(name="rules_proto_grpc", version="5.0.0")

archive_override(
    module_name = "rules_proto_grpc",
    strip_prefix = "rules_proto_grpc-5.0.0-alpha3",
    urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/5.0.0-alpha3/rules_proto_grpc-5.0.0-alpha3.tar.gz"],
)

bazel_dep(name="rules_proto_grpc_python", version="5.0.0")

archive_override(
    module_name = "rules_proto_grpc_python",
    integrity = "sha256-sQGn6Ph87GEHSkRSQSOauo1nouRJFEmYT5PlSL/EASI=",
    strip_prefix = "rules_proto_grpc_python-5.0.0-alpha3",
    urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/5.0.0-alpha3/rules_proto_grpc_python-5.0.0-alpha3.tar.gz"],
)

BUILD Content

load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_proto_grpc_python//:defs.bzl", "python_grpc_library")
load("@rules_python//python:defs.bzl", "py_test")

package(default_visibility = ["//visibility:private"])

# Test that python 3 dependencies protobuf and grpc are importable

proto_library(
    name = "proto_lib",
    srcs = ["demo.proto"],
)

python_grpc_library(
    name = "py_lib",
    protos = [":proto_lib"],
    python_version = "PY3",
)

py_test(
    name = "test",
    srcs = ["test.py"],
    legacy_create_init = False,
    python_version = "PY3",
    deps = [":py_lib"],
)

Proto Content

syntax = "proto3";

message demo {
    bool field = 1;
}

service K8s {
}

Any Other Content

-- MODULE.bazel --
module(name="k8s_test")

bazel_dep(name="rules_python", version="0.28.0")
bazel_dep(name="rules_proto_grpc", version="5.0.0")

archive_override(
    module_name = "rules_proto_grpc",
    strip_prefix = "rules_proto_grpc-5.0.0-alpha3",
    urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/5.0.0-alpha3/rules_proto_grpc-5.0.0-alpha3.tar.gz"],
)

bazel_dep(name="rules_proto_grpc_python", version="5.0.0")

archive_override(
    module_name = "rules_proto_grpc_python",
    integrity = "sha256-sQGn6Ph87GEHSkRSQSOauo1nouRJFEmYT5PlSL/EASI=",
    strip_prefix = "rules_proto_grpc_python-5.0.0-alpha3",
    urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/5.0.0-alpha3/rules_proto_grpc_python-5.0.0-alpha3.tar.gz"],
)
-- WORKSPACE --
-- k8s.io/apimachinary/BUILD.bazel --
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_proto_grpc_python//:defs.bzl", "python_grpc_library")
load("@rules_python//python:defs.bzl", "py_test")

package(default_visibility = ["//visibility:private"])

# Test that python 3 dependencies protobuf and grpc are importable

proto_library(
    name = "proto_lib",
    srcs = ["demo.proto"],
)

python_grpc_library(
    name = "py_lib",
    protos = [":proto_lib"],
    python_version = "PY3",
)

py_test(
    name = "test",
    srcs = ["test.py"],
    legacy_create_init = False,
    python_version = "PY3",
    deps = [":py_lib"],
)
-- k8s.io/apimachinary/demo.proto --
syntax = "proto3";

message demo {
    bool field = 1;
}

service K8s {
}
-- k8s.io/apimachinary/test.py --
import unittest

class TestImports(unittest.TestCase):
    def test_import_pb2(self):
        from k8s.io.apimachinary import demo_pb2
        self.assertGreater(len(dir(demo_pb2)), 0)


    def test_import_pb2(self):
        from k8s.io.apimachinary import demo_pb2_grpc
        self.assertGreater(len(dir(demo_pb2_grpc)), 0)


if __name__ == "__main__":
    unittest.main()
@SDAChess
Copy link

I am also looking for an update on this issue. Could it be possible to add the same default as for protobuf generation which generates by default the subdirectories automatically?

@SDAChess
Copy link

I don't mind fixing the issue if you give me the go on how you want it fixed.

@linzhp
Copy link
Contributor Author

linzhp commented Mar 22, 2024

@aaliddell what do you think?

@aaliddell
Copy link
Member

aaliddell commented Mar 25, 2024

So I had a dig through the protobuf and grpc code to see where this was coming from when I was reviewing your PR. This is the draft message I was part way through writing and haven't had time recently to come back to sorry:

I've been looking through the Python compiler protoc plugins for protobuf and grpc and this seems like a bug in the grpc plugin, since it makes no attempt to replace the dots to make an importable path here:

https://github.com/grpc/grpc/blob/5174569c4d3352112848f1b86ba259425db939cf/src/compiler/python_generator.cc#L892-L900

The protobuf plugin does however patch dots into slashes:

https://github.com/protocolbuffers/protobuf/blob/a9b006bddd52e289029f16aa77b77e8e0033d9ee/src/google/protobuf/compiler/python/helpers.cc#L79

And the grpc plugin is aware that the protouf plugin does this:

https://github.com/grpc/grpc/blob/5174569c4d3352112848f1b86ba259425db939cf/src/compiler/python_generator_helpers.h#L64-L75

So if anything, the lack of support for dotted paths here is a symptom of a problem elsewhere and the relevant bug is here: grpc/grpc#23978

So regarding the PR, I'm hesitant to put in a fix that makes the plugins behave differently here than they do elsewhere, as that then becomes a divergent implementation.

On that last point: what's the non-Bazel gRPC way of solving this with Python? i.e if you are running grpcio-tools yourself, how would you be expected to fix this? The hesitancy comes having to patch the import paths and introduce some "magic" that doesn't work outside of Bazel, especially since the code is changing the way NO_PREFIX_FLAT is behaving too.

@SDAChess
Copy link

SDAChess commented Apr 2, 2024

I'll try to get a patch merged upstream so that it fixes at least the path problem on gRPC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants