Skip to content

Commit

Permalink
fix(gazelle): Do not create invalid py_test rules in project genera…
Browse files Browse the repository at this point in the history
…tion mode (#1809)

Since bazelbuild/rules_python#1538, when using
`gazelle:python_generation_mode project`, a `py_test` rule is created
even when there are no test files in the project.
fb673ee47b3268a65a18a154edd574b6509c38c7 (first commit on the PR branch)
reproduces this issue - it shows that a `py_test` rule is created even
when there is no test entrypoint file (`__test__.py`) nor any test file
in the entire project. Additionally, test rules created on `project` or
`package` generation mode will always set `main = "__test__.py"`, even
when that file doesn't exist.

This PR fixes it by only generating a `py_test` rule if it can find some
test file - either an explicit `__test__.py`, or any other file prefixed
with `test_` or suffixed with `_test.py`. It also changes the generated
test rule to only add `main = "__test__.py"` if there is an actual
`__test__.py` file. Note that, in the case where a `__test__.py` file
doesn't exist, the generated `py_test` rule is likely invalid as-is due
to the lack of `main`; this can be fixed by mapping to some other
`py_test` implementation, and I believe the new behavior makes more
sense than pointing `main` to a non-existing file.

It may be useful to review per-commit (all tests pass on each commit):
- First commit reproduces the issue;
- Second commit fixes the issue and the corresponding tests;
- Third commit adds additional test cases.
  • Loading branch information
amartani authored Mar 21, 2024
1 parent 150dc2a commit dc4407c
Show file tree
Hide file tree
Showing 25 changed files with 130 additions and 14 deletions.
28 changes: 15 additions & 13 deletions python/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,20 +393,22 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
// the file exists on disk.
pyTestFilenames.Add(pyTestEntrypointFilename)
}
pyTestTargetName := cfg.RenderTestName(packageName)
pyTestTarget := newPyTestTargetBuilder(pyTestFilenames, pyTestTargetName)

if hasPyTestEntryPointTarget {
entrypointTarget := fmt.Sprintf(":%s", pyTestEntrypointTargetname)
main := fmt.Sprintf(":%s", pyTestEntrypointFilename)
pyTestTarget.
addSrc(entrypointTarget).
addResolvedDependency(entrypointTarget).
setMain(main)
} else {
pyTestTarget.setMain(pyTestEntrypointFilename)
if (hasPyTestEntryPointTarget || !pyTestFilenames.Empty()) {
pyTestTargetName := cfg.RenderTestName(packageName)
pyTestTarget := newPyTestTargetBuilder(pyTestFilenames, pyTestTargetName)

if hasPyTestEntryPointTarget {
entrypointTarget := fmt.Sprintf(":%s", pyTestEntrypointTargetname)
main := fmt.Sprintf(":%s", pyTestEntrypointFilename)
pyTestTarget.
addSrc(entrypointTarget).
addResolvedDependency(entrypointTarget).
setMain(main)
} else if hasPyTestEntryPointFile {
pyTestTarget.setMain(pyTestEntrypointFilename)
}
pyTestTargets = append(pyTestTargets, pyTestTarget)
}
pyTestTargets = append(pyTestTargets, pyTestTarget)
} else {
// Create one py_test target per file
pyTestFilenames.Each(func(index int, testFile interface{}) {
Expand Down
1 change: 0 additions & 1 deletion python/testdata/monorepo/coarse_grained/BUILD.out
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,4 @@ py_test(
"bar/bar_test.py",
"foo/bar/bar_test.py",
],
main = "__test__.py",
)
2 changes: 2 additions & 0 deletions python/testdata/project_generation_mode/BUILD.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# gazelle:python_extension enabled
# gazelle:python_generation_mode project
14 changes: 14 additions & 0 deletions python/testdata/project_generation_mode/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
load("@rules_python//python:defs.bzl", "py_library")

# gazelle:python_extension enabled
# gazelle:python_generation_mode project

py_library(
name = "project_generation_mode",
srcs = [
"__init__.py",
"bar/bar.py",
"foo/foo.py",
],
visibility = ["//:__subpackages__"],
)
3 changes: 3 additions & 0 deletions python/testdata/project_generation_mode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Project generation mode

Simple example using `gazelle:python_generation_mode project` in a project with no tests.
1 change: 1 addition & 0 deletions python/testdata/project_generation_mode/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
Empty file.
Empty file.
Empty file.
15 changes: 15 additions & 0 deletions python/testdata/project_generation_mode/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# gazelle:python_extension enabled
# gazelle:python_generation_mode project
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
load("@rules_python//python:defs.bzl", "py_library", "py_test")

# gazelle:python_extension enabled
# gazelle:python_generation_mode project

py_library(
name = "project_generation_mode_with_test_entrypoint",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
)

py_test(
name = "project_generation_mode_with_test_entrypoint_test",
srcs = [
"__test__.py",
"foo/foo_test.py",
],
main = "__test__.py",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Project generation mode with test entrypoint

Example using `gazelle:python_generation_mode project` in a project with tests that use an explicit `__test__.py` entrypoint.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---
2 changes: 2 additions & 0 deletions python/testdata/project_generation_mode_with_tests/BUILD.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# gazelle:python_extension enabled
# gazelle:python_generation_mode project
15 changes: 15 additions & 0 deletions python/testdata/project_generation_mode_with_tests/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@rules_python//python:defs.bzl", "py_library", "py_test")

# gazelle:python_extension enabled
# gazelle:python_generation_mode project

py_library(
name = "project_generation_mode_with_tests",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
)

py_test(
name = "project_generation_mode_with_tests_test",
srcs = ["foo/foo_test.py"],
)
7 changes: 7 additions & 0 deletions python/testdata/project_generation_mode_with_tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Project generation mode with tests

Example using `gazelle:python_generation_mode project` in a project with tests, but no `__test__.py` entrypoint.

Note that, in this mode, the `py_test` rule will have no `main` set, which will fail to run with the standard
`py_test` rule. However, this can be used in conjunction with `gazelle:map_kind` to use some other implementation
of `py_test` that is able to handle this sitation (such as `rules_python_pytest`).
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
Empty file.
Empty file.
15 changes: 15 additions & 0 deletions python/testdata/project_generation_mode_with_tests/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---

0 comments on commit dc4407c

Please sign in to comment.