Skip to content

Commit dd6550f

Browse files
feat(gazelle): Gazelle plugin generates py_proto_library (#3057)
Fixes #2994. Please go over this with a fine-toothed comb! This is my first contribution to `rules_python` / the gazelle plugin, and while I've worked in Gazelle before, I'm pretty unfamiliar with the Python plugin's architecture. This adds support in the Gazelle plugin for generating `py_proto_library` rules automatically, if there are any `proto_library` rules detected in a given package. We do this via a new Gazelle directive, `python_generate_proto`, which defaults to `true`, and controls whether these rules are generated. See the tests in `testdata/directive_python_generate_proto` for examples. By default, we source the `py_proto_library` rule from the `@protobuf` repository. I think this the intended long-term home of the rule? Users are expected to use `gazelle:map_kind` to change this if need be. I haven't done anything here to support resolution of imports of `py_proto_library`. I think this is worth landing first, to save folks from having to maintain these by hand. But this should lay the foundation for resolving that in #1703. --------- Co-authored-by: Douglas Thor <[email protected]>
1 parent 6f27511 commit dd6550f

File tree

50 files changed

+412
-26
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+412
-26
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ END_UNRELEASED_TEMPLATE
106106
* 3.12.11
107107
* 3.13.5
108108
* 3.14.0b3
109+
* (gazelle) New directive `gazelle:python_generate_proto`; when `true`,
110+
Gazelle generates `py_proto_library` rules for `proto_library`. `false` by default.
109111

110112
{#v0-0-0-removed}
111113
### Removed

examples/bzlmod/py_proto_library/BUILD.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ py_test(
66
srcs = ["test.py"],
77
main = "test.py",
88
deps = [
9-
"//py_proto_library/example.com/proto:pricetag_proto_py_pb2",
9+
"//py_proto_library/example.com/proto:pricetag_py_pb2",
1010
],
1111
)
1212

1313
py_test(
1414
name = "message_test",
1515
srcs = ["message_test.py"],
1616
deps = [
17-
"//py_proto_library/example.com/another_proto:message_proto_py_pb2",
17+
"//py_proto_library/example.com/another_proto:message_py_pb2",
1818
],
1919
)
2020

examples/bzlmod/py_proto_library/example.com/another_proto/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
22
load("@rules_python//python:proto.bzl", "py_proto_library")
33

44
py_proto_library(
5-
name = "message_proto_py_pb2",
5+
name = "message_py_pb2",
66
visibility = ["//visibility:public"],
77
deps = [":message_proto"],
88
)

examples/bzlmod/py_proto_library/example.com/proto/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
22
load("@rules_python//python:proto.bzl", "py_proto_library")
33

44
py_proto_library(
5-
name = "pricetag_proto_py_pb2",
5+
name = "pricetag_py_pb2",
66
visibility = ["//visibility:public"],
77
deps = [":pricetag_proto"],
88
)

examples/py_proto_library/BUILD.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ py_test(
55
srcs = ["test.py"],
66
main = "test.py",
77
deps = [
8-
"//example.com/proto:pricetag_proto_py_pb2",
8+
"//example.com/proto:pricetag_py_pb2",
99
],
1010
)
1111

1212
py_test(
1313
name = "message_test",
1414
srcs = ["message_test.py"],
1515
deps = [
16-
"//example.com/another_proto:message_proto_py_pb2",
16+
"//example.com/another_proto:message_py_pb2",
1717
],
1818
)

examples/py_proto_library/example.com/another_proto/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
22
load("@rules_python//python:proto.bzl", "py_proto_library")
33

44
py_proto_library(
5-
name = "message_proto_py_pb2",
5+
name = "message_py_pb2",
66
visibility = ["//visibility:public"],
77
deps = [":message_proto"],
88
)

examples/py_proto_library/example.com/proto/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
22
load("@rules_python//python:proto.bzl", "py_proto_library")
33

44
py_proto_library(
5-
name = "pricetag_proto_py_pb2",
5+
name = "pricetag_py_pb2",
66
visibility = ["//visibility:public"],
77
deps = [":pricetag_proto"],
88
)

gazelle/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ Python-specific directives are as follows:
224224
| Controls whether Gazelle resolves dependencies for import statements that use paths relative to the current package. Can be "true" or "false".|
225225
| `# gazelle:python_generate_pyi_deps` | `false` |
226226
| Controls whether to generate a separate `pyi_deps` attribute for type-checking dependencies or merge them into the regular `deps` attribute. When `false` (default), type-checking dependencies are merged into `deps` for backward compatibility. When `true`, generates separate `pyi_deps`. Imports in blocks with the format `if typing.TYPE_CHECKING:`/`if TYPE_CHECKING:` and type-only stub packages (eg. boto3-stubs) are recognized as type-checking dependencies. |
227+
| [`# gazelle:python_generate_proto`](#directive-python_generate_proto) | `false` |
228+
| Controls whether to generate a `py_proto_library` for each `proto_library` in the package. By default we load this rule from the `@protobuf` repository; use `gazelle:map_kind` if you need to load this from somewhere else. |
227229

228230
#### Directive: `python_root`:
229231

@@ -484,6 +486,41 @@ def py_test(name, main=None, **kwargs):
484486
)
485487
```
486488

489+
#### Directive: `python_generate_proto`:
490+
491+
When `# gazelle:python_generate_proto true`, Gazelle will generate one
492+
`py_proto_library` for each `proto_library`, generating Python clients for
493+
protobuf in each package. By default this is turned off. Gazelle will also
494+
generate a load statement for the `py_proto_library` - attempting to detect
495+
the configured name for the `@protobuf` / `@com_google_protobuf` repo in your
496+
`MODULE.bazel`, and otherwise falling back to `@com_google_protobuf` for
497+
compatibility with `WORKSPACE`.
498+
499+
For example, in a package with `# gazelle:python_generate_proto true` and a
500+
`foo.proto`, if you have both the proto extension and the Python extension
501+
loaded into Gazelle, you'll get something like:
502+
503+
```starlark
504+
load("@protobuf//bazel:py_proto_library.bzl", "py_proto_library")
505+
load("@rules_proto//proto:defs.bzl", "proto_library")
506+
507+
# gazelle:python_generate_proto true
508+
509+
proto_library(
510+
name = "foo_proto",
511+
srcs = ["foo.proto"],
512+
visibility = ["//:__subpackages__"],
513+
)
514+
515+
py_proto_library(
516+
name = "foo_py_pb2",
517+
visibility = ["//:__subpackages__"],
518+
deps = [":foo_proto"],
519+
)
520+
```
521+
522+
When `false`, Gazelle will ignore any `py_proto_library`, including previously-generated or hand-created rules.
523+
487524
### Annotations
488525

489526
*Annotations* refer to comments found _within Python files_ that configure how

gazelle/python/BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ go_library(
3434
"@bazel_gazelle//config:go_default_library",
3535
"@bazel_gazelle//label:go_default_library",
3636
"@bazel_gazelle//language:go_default_library",
37+
"@bazel_gazelle//language/proto:go_default_library",
3738
"@bazel_gazelle//repo:go_default_library",
3839
"@bazel_gazelle//resolve:go_default_library",
3940
"@bazel_gazelle//rule:go_default_library",
@@ -91,7 +92,10 @@ gazelle_test(
9192

9293
gazelle_binary(
9394
name = "gazelle_binary",
94-
languages = [":python"],
95+
languages = [
96+
"@bazel_gazelle//language/proto",
97+
":python",
98+
],
9599
visibility = ["//visibility:public"],
96100
)
97101

gazelle/python/configure.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func (py *Configurer) KnownDirectives() []string {
7070
pythonconfig.LabelNormalization,
7171
pythonconfig.GeneratePyiDeps,
7272
pythonconfig.ExperimentalAllowRelativeImports,
73+
pythonconfig.GenerateProto,
7374
}
7475
}
7576

@@ -237,6 +238,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
237238
log.Fatal(err)
238239
}
239240
config.SetGeneratePyiDeps(v)
241+
case pythonconfig.GenerateProto:
242+
v, err := strconv.ParseBool(strings.TrimSpace(d.Value))
243+
if err != nil {
244+
log.Fatal(err)
245+
}
246+
config.SetGenerateProto(v)
240247
}
241248
}
242249

0 commit comments

Comments
 (0)