fix(gazelle): ensure that gazelle helper modules are on PYTHONPATH (#1590) Before this change there was a bug in how the parsing helpers were being used in case we were using Python 3.11 toolchain, which is using a more strict version of the entrypoint template. This change adds `imports = ["."]` to ensure that the gazelle helper components are on PYTHONPATH and updates the non-bzlmod tests to run under 3.11. We also: * Change `.bazelrc` to use explicit `__init__.py` definition to avoid non-reproducible errors in the future. * Add a dedicated `gazelle_binary` that uses `DEFAULT_LANGUAGES` *and* `//python`. Fixes #1589
diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ab939..ca8276f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -17,9 +17,14 @@ * Particular sub-systems are identified using parentheses, e.g. `(bzlmod)` or `(docs)`. -## Unreleased +## [0.27.1] - 2023-12-05 -[0.XX.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.XX.0 +[0.27.1]: https://github.com/bazelbuild/rules_python/releases/tag/0.27.1 + +### Fixed + +* (gazelle) The gazelle plugin helper was not working with Python toolchains 3.11 + and above due to a bug in the helper components not being on `PYTHONPATH`. ## [0.27.0] - 2023-11-16
diff --git a/gazelle/.bazelrc b/gazelle/.bazelrc index f48d0a9..7a67d3e 100644 --- a/gazelle/.bazelrc +++ b/gazelle/.bazelrc
@@ -11,3 +11,11 @@ # Windows makes use of runfiles for some rules build --enable_runfiles startup --windows_enable_symlinks + +# Do NOT implicitly create empty __init__.py files in the runfiles tree. +# By default, these are created in every directory containing Python source code +# or shared libraries, and every parent directory of those directories, +# excluding the repo root directory. With this flag set, we are responsible for +# creating (possibly empty) __init__.py files and adding them to the srcs of +# Python targets as required. +build --incompatible_default_to_explicit_init_py
diff --git a/gazelle/BUILD.bazel b/gazelle/BUILD.bazel index 6016145..7a4d4c0 100644 --- a/gazelle/BUILD.bazel +++ b/gazelle/BUILD.bazel
@@ -1,10 +1,18 @@ -load("@bazel_gazelle//:def.bzl", "gazelle") +load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle", "gazelle_binary") # Gazelle configuration options. # See https://github.com/bazelbuild/bazel-gazelle#running-gazelle-with-bazel # gazelle:prefix github.com/bazelbuild/rules_python/gazelle # gazelle:exclude bazel-out -gazelle(name = "gazelle") +gazelle( + name = "gazelle", + gazelle = ":gazelle_binary", +) + +gazelle_binary( + name = "gazelle_binary", + languages = DEFAULT_LANGUAGES + ["//python"], +) gazelle( name = "gazelle_update_repos",
diff --git a/gazelle/WORKSPACE b/gazelle/WORKSPACE index fe7ac3e..df2883f 100644 --- a/gazelle/WORKSPACE +++ b/gazelle/WORKSPACE
@@ -39,8 +39,8 @@ py_repositories() python_register_toolchains( - name = "python39", - python_version = "3.9", + name = "python_3_11", + python_version = "3.11", ) load("//:deps.bzl", _py_gazelle_deps = "gazelle_deps")
diff --git a/gazelle/modules_mapping/BUILD.bazel b/gazelle/modules_mapping/BUILD.bazel index 1855551..d78b1fb 100644 --- a/gazelle/modules_mapping/BUILD.bazel +++ b/gazelle/modules_mapping/BUILD.bazel
@@ -1,5 +1,7 @@ load("@rules_python//python:defs.bzl", "py_binary") +# gazelle:exclude *.py + py_binary( name = "generator", srcs = ["generator.py"],
diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel index e993a14..1d9460c 100644 --- a/gazelle/python/BUILD.bazel +++ b/gazelle/python/BUILD.bazel
@@ -17,7 +17,15 @@ "std_modules.go", "target.go", ], - embedsrcs = [":helper.zip"], + # NOTE @aignas 2023-12-03: currently gazelle does not support embedding + # generated files, but helper.zip is generated by a build rule. + # + # You will get a benign error like when running gazelle locally: + # > 8 gazelle: .../rules_python/gazelle/python/lifecycle.go:26:3: pattern helper.zip: matched no files + # + # See following for more info: + # https://github.com/bazelbuild/bazel-gazelle/issues/1513 + embedsrcs = [":helper.zip"], # keep importpath = "github.com/bazelbuild/rules_python/gazelle/python", visibility = ["//visibility:public"], deps = [ @@ -44,6 +52,8 @@ "parse.py", "std_modules.py", ], + # This is to make sure that the current directory is added to PYTHONPATH + imports = ["."], main = "__main__.py", visibility = ["//visibility:public"], ) @@ -54,6 +64,8 @@ output_group = "python_zip_file", ) +# gazelle:exclude testdata/ + gazelle_test( name = "python_test", srcs = ["python_test.go"],
diff --git a/gazelle/python/__main__.py b/gazelle/python/__main__.py index 2f5a4a1..18bc1ca 100644 --- a/gazelle/python/__main__.py +++ b/gazelle/python/__main__.py
@@ -16,9 +16,10 @@ # STDIN receives parse requests, one per line. It outputs the parsed modules and # comments from all the files from each request. +import sys + import parse import std_modules -import sys if __name__ == "__main__": if len(sys.argv) < 2:
diff --git a/gazelle/python/python_test.go b/gazelle/python/python_test.go index 74bd85b..617b3f8 100644 --- a/gazelle/python/python_test.go +++ b/gazelle/python/python_test.go
@@ -162,7 +162,7 @@ cmd.Dir = workspaceRoot helperScript, err := runfiles.Rlocation("rules_python_gazelle_plugin/python/helper") if err != nil { - t.Fatalf("failed to initialize Python heler: %v", err) + t.Fatalf("failed to initialize Python helper: %v", err) } cmd.Env = append(os.Environ(), "GAZELLE_PYTHON_HELPER="+helperScript) if err := cmd.Run(); err != nil {
diff --git a/gazelle/pythonconfig/BUILD.bazel b/gazelle/pythonconfig/BUILD.bazel index d0f1690..d80902e 100644 --- a/gazelle/pythonconfig/BUILD.bazel +++ b/gazelle/pythonconfig/BUILD.bazel
@@ -18,7 +18,7 @@ go_test( name = "pythonconfig_test", srcs = ["pythonconfig_test.go"], - deps = [":pythonconfig"], + embed = [":pythonconfig"], ) filegroup(
diff --git a/gazelle/pythonconfig/pythonconfig_test.go b/gazelle/pythonconfig/pythonconfig_test.go index 1512eb9..bf31106 100644 --- a/gazelle/pythonconfig/pythonconfig_test.go +++ b/gazelle/pythonconfig/pythonconfig_test.go
@@ -2,8 +2,6 @@ import ( "testing" - - "github.com/bazelbuild/rules_python/gazelle/pythonconfig" ) func TestDistributionSanitizing(t *testing.T) { @@ -19,7 +17,7 @@ for name, tc := range tests { t.Run(name, func(t *testing.T) { - got := pythonconfig.SanitizeDistribution(tc.input) + got := SanitizeDistribution(tc.input) if tc.want != got { t.Fatalf("expected %q, got %q", tc.want, got) }