fix: Fix per-file config interaction with one py_binary per main (#1664)
[This previous PR](https://github.com/bazelbuild/rules_python/pull/1584)
added the ability to make a `py_binary` target per file if `if __name__
== "__main__"` tokens were found in the file. This works great in the
default case, but when `python_generation_mode` is set to `file`, the
plugin now attempts to make both a `py_binary` and a `py_library` target
for each main file, which results in an error.
This PR modifies the behavior to work properly with per-file target
generation, and adds tests for this case.
diff --git a/gazelle/python/generate.go b/gazelle/python/generate.go
index 95f5396..ba273be 100644
--- a/gazelle/python/generate.go
+++ b/gazelle/python/generate.go
@@ -225,23 +225,17 @@
log.Fatalf("ERROR: %v\n", err)
}
- // Check if a target with the same name we are generating already
- // exists, and if it is of a different kind from the one we are
- // generating. If so, we have to throw an error since Gazelle won't
- // generate it correctly.
- if err := ensureNoCollision(args.File, pyLibraryTargetName, actualPyLibraryKind); err != nil {
- fqTarget := label.New("", args.Rel, pyLibraryTargetName)
- err := fmt.Errorf("failed to generate target %q of kind %q: %w. "+
- "Use the '# gazelle:%s' directive to change the naming convention.",
- fqTarget.String(), actualPyLibraryKind, err, pythonconfig.LibraryNamingConvention)
- collisionErrors.Add(err)
- }
-
if !hasPyBinaryEntryPointFile {
// Creating one py_binary target per main module when __main__.py doesn't exist.
mainFileNames := make([]string, 0, len(mainModules))
for name := range mainModules {
mainFileNames = append(mainFileNames, name)
+
+ // Remove the file from srcs if we're doing per-file library generation so
+ // that we don't also generate a py_library target for it.
+ if cfg.PerFileGeneration() {
+ srcs.Remove(name)
+ }
}
sort.Strings(mainFileNames)
for _, filename := range mainFileNames {
@@ -262,6 +256,23 @@
}
}
+ // If we're doing per-file generation, srcs could be empty at this point, meaning we shouldn't make a py_library.
+ if srcs.Empty() {
+ return
+ }
+
+ // Check if a target with the same name we are generating already
+ // exists, and if it is of a different kind from the one we are
+ // generating. If so, we have to throw an error since Gazelle won't
+ // generate it correctly.
+ if err := ensureNoCollision(args.File, pyLibraryTargetName, actualPyLibraryKind); err != nil {
+ fqTarget := label.New("", args.Rel, pyLibraryTargetName)
+ err := fmt.Errorf("failed to generate target %q of kind %q: %w. "+
+ "Use the '# gazelle:%s' directive to change the naming convention.",
+ fqTarget.String(), actualPyLibraryKind, err, pythonconfig.LibraryNamingConvention)
+ collisionErrors.Add(err)
+ }
+
pyLibrary := newTargetBuilder(pyLibraryKind, pyLibraryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
addVisibility(visibility).
addSrcs(srcs).