danielgtaylor / python-betterproto

Clean, modern, Python 3.6+ code generator & library for Protobuf 3 and async gRPC
MIT License
1.5k stars 209 forks source link

Bazel? #492

Closed ramilmsh closed 1 year ago

ramilmsh commented 1 year ago

Hi! I am managing a bazel monorepo and I would like to know if there are any predefined bazel rules for this plugin?

ramilmsh commented 1 year ago

So, i've advanced a bit on this issue and i was able to add betterproto to my workspace by using rules_proto_grpc and rules_python

betterproto.bzl

load("@rules_proto//proto:defs.bzl", "ProtoInfo")
load(
    "@rules_proto_grpc//:defs.bzl",
    "ProtoPluginInfo",
    "proto_compile_attrs",
    "proto_compile_impl",
)

compile = rule(
    implementation = proto_compile_impl,
    attrs = dict(
        proto_compile_attrs,
        _plugins = attr.label_list(
            providers = [ProtoPluginInfo],
            default = [
                Label(":python_betterproto"),
            ],
            doc = "Generate pydantic models",
        ),
    ),
    toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))],
)

BUILD

load("@rules_proto_grpc//:defs.bzl", "proto_plugin")

proto_plugin(
    name = "python_betterproto",
    options = ["pydantic_dataclasses"],
    output_directory = True,
    tool = "@pip_betterproto//:rules_python_wheel_entry_point_protoc-gen-python_betterproto",
    visibility = ["//visibility:public"],
)

another BUILD next to proto files

proto_library(
    name = "proto_proto",
    srcs = [
        ....
    ],
    visibility = ["//visibility:public"],
    deps = [
         ...
    ],
)

betterproto_compile(
    name = "proto_betterproto_proto",
    protos = [":proto_proto"],
    visibility = ["//visibility:public"],
)

...
copy outputs of `proto_betterproto_proto` back into workspace

This generates the files just fine, and all seems to work fine.

i ran into 2 more issues:

  1. The other modules are imported via dot imports, instead of global imports. So if you have 2 proto packages one a.b and a.c, which depends on a.b. a.c will import a.b by doing from .. import b. Gazelle doesn't seem to handle this well, however, by adding imports manually and then adding # keep i seem to have resolved that ok
  2. The generated files don't seem to match proto files 1-1, which makes integration a little more complicated, but output_directory = True helps

Maybe I will fix them later

ramilmsh commented 1 year ago

I think i will close now, since it doesn't seem like there will be a different answer and my issue appears to be resolved

jasonprado commented 3 weeks ago

@ramilmsh Can you share your definition of betterproto_compile as well?

ramilmsh commented 2 weeks ago

@jasonprado just for you

https://github.com/ramilmsh/betterproto-example

This is in no way a production setup i'd use, but should be enough to get you started

basic idea:

  1. get rules_proto_grpc (simplifies rules)
  2. create a custom plugin for betterproto
  3. compile the protos
  4. write them back to source and turn them into python libraries via gazelle

This is NOT a good idea. Because that means that we no longer guarantee correctness (are they up-to-date or not) of the generated files, but i'm lazy and i didn't wanna spend time fixing that. Proper approach would be to gazelle ignore the entire generated folder, and create a python library rule in the parent directory based on generated files directly. But i'm short on time