Skip to content

Commit 5667a86

Browse files
authored
feat(gazelle): Add "python_test_file_pattern" directive (#1819)
Add the `python_test_file_pattern` directive. This directive allows users to configure what python files get mapped to the `py_test` rule. The default behavior is unchanged: both `test_*` and `*_test.py` files generate `py_test` targets if the directive is unset. The directive supports multiple glob patterns, separated by a comma. Note: The original code used, effectively, `test_*` for one of the patterns. This code uses `test_*.py` instead. These are equivalent because of the `.py` extension check prior to pattern matching. Fixes #1816.
1 parent 9e38b65 commit 5667a86

Some content is hidden

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

63 files changed

+362
-14
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions

gazelle/MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ go_deps.from_file(go_mod = "//:go.mod")
1414
use_repo(
1515
go_deps,
1616
"com_github_bazelbuild_buildtools",
17-
"com_github_bmatcuk_doublestar",
17+
"com_github_bmatcuk_doublestar_v4",
1818
"com_github_emirpasic_gods",
1919
"com_github_ghodss_yaml",
2020
"in_gopkg_yaml_v2",

gazelle/README.md

Lines changed: 67 additions & 1 deletion

gazelle/deps.bzl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ def gazelle_deps():
3838
)
3939

4040
go_repository(
41-
name = "com_github_bmatcuk_doublestar",
42-
importpath = "github.com/bmatcuk/doublestar",
43-
sum = "h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=",
44-
version = "v1.3.4",
41+
name = "com_github_bmatcuk_doublestar_v4",
42+
importpath = "github.com/bmatcuk/doublestar/v4",
43+
sum = "h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=",
44+
version = "v4.6.1",
4545
)
4646

4747
go_repository(

gazelle/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/bazelbuild/bazel-gazelle v0.31.1
77
github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d
88
github.com/bazelbuild/rules_go v0.41.0
9-
github.com/bmatcuk/doublestar v1.3.4
9+
github.com/bmatcuk/doublestar/v4 v4.6.1
1010
github.com/emirpasic/gods v1.18.1
1111
github.com/ghodss/yaml v1.0.0
1212
gopkg.in/yaml.v2 v2.4.0

gazelle/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d h1:Fl1FfItZp
66
github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d/go.mod h1:689QdV3hBP7Vo9dJMmzhoYIyo/9iMhEmHkJcnaPRCbo=
77
github.com/bazelbuild/rules_go v0.41.0 h1:JzlRxsFNhlX+g4drDRPhIaU5H5LnI978wdMJ0vK4I+k=
88
github.com/bazelbuild/rules_go v0.41.0/go.mod h1:TMHmtfpvyfsxaqfL9WnahCsXMWDMICTw7XeK9yVb+YU=
9-
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
10-
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
9+
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
10+
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
1111
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
1212
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
1313
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=

gazelle/python/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ go_library(
3838
"@bazel_gazelle//resolve:go_default_library",
3939
"@bazel_gazelle//rule:go_default_library",
4040
"@com_github_bazelbuild_buildtools//build:go_default_library",
41-
"@com_github_bmatcuk_doublestar//:doublestar",
41+
"@com_github_bmatcuk_doublestar_v4//:doublestar",
4242
"@com_github_emirpasic_gods//lists/singlylinkedlist",
4343
"@com_github_emirpasic_gods//sets/treeset",
4444
"@com_github_emirpasic_gods//utils",

gazelle/python/configure.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/bazelbuild/bazel-gazelle/config"
2727
"github.com/bazelbuild/bazel-gazelle/rule"
28+
"github.com/bmatcuk/doublestar/v4"
2829

2930
"github.com/bazelbuild/rules_python/gazelle/manifest"
3031
"github.com/bazelbuild/rules_python/gazelle/pythonconfig"
@@ -65,6 +66,7 @@ func (py *Configurer) KnownDirectives() []string {
6566
pythonconfig.TestNamingConvention,
6667
pythonconfig.DefaultVisibilty,
6768
pythonconfig.Visibility,
69+
pythonconfig.TestFilePattern,
6870
}
6971
}
7072

@@ -181,6 +183,18 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
181183
}
182184
case pythonconfig.Visibility:
183185
config.AppendVisibility(strings.TrimSpace(d.Value))
186+
case pythonconfig.TestFilePattern:
187+
value := strings.TrimSpace(d.Value)
188+
if value == "" {
189+
log.Fatal("directive 'python_test_file_pattern' requires a value")
190+
}
191+
globStrings := strings.Split(value, ",")
192+
for _, g := range globStrings {
193+
if !doublestar.ValidatePattern(g) {
194+
log.Fatalf("invalid glob pattern '%s'", g)
195+
}
196+
}
197+
config.SetTestFilePattern(globStrings)
184198
}
185199
}
186200

gazelle/python/generate.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"github.com/bazelbuild/bazel-gazelle/language"
2929
"github.com/bazelbuild/bazel-gazelle/rule"
3030
"github.com/bazelbuild/rules_python/gazelle/pythonconfig"
31-
"github.com/bmatcuk/doublestar"
31+
"github.com/bmatcuk/doublestar/v4"
3232
"github.com/emirpasic/gods/lists/singlylinkedlist"
3333
"github.com/emirpasic/gods/sets/treeset"
3434
godsutils "github.com/emirpasic/gods/utils"
@@ -54,6 +54,17 @@ func GetActualKindName(kind string, args language.GenerateArgs) string {
5454
return kind
5555
}
5656

57+
func matchesAnyGlob(s string, globs []string) bool {
58+
// This function assumes that the globs have already been validated. If a glob is
59+
// invalid, it's considered a non-match and we move on to the next pattern.
60+
for _, g := range globs {
61+
if ok, _ := doublestar.Match(g, s); ok {
62+
return true
63+
}
64+
}
65+
return false
66+
}
67+
5768
// GenerateRules extracts build metadata from source files in a directory.
5869
// GenerateRules is called in each directory where an update is requested
5970
// in depth-first post-order.
@@ -100,6 +111,8 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
100111
hasPyTestEntryPointTarget := false
101112
hasConftestFile := false
102113

114+
testFileGlobs := cfg.TestFilePattern()
115+
103116
for _, f := range args.RegularFiles {
104117
if cfg.IgnoresFile(filepath.Base(f)) {
105118
continue
@@ -113,7 +126,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
113126
hasPyTestEntryPointFile = true
114127
} else if f == conftestFilename {
115128
hasConftestFile = true
116-
} else if strings.HasSuffix(f, "_test.py") || strings.HasPrefix(f, "test_") {
129+
} else if matchesAnyGlob(f, testFileGlobs) {
117130
pyTestFilenames.Add(f)
118131
} else {
119132
pyLibraryFilenames.Add(f)
@@ -195,7 +208,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
195208
}
196209
}
197210
baseName := filepath.Base(path)
198-
if strings.HasSuffix(baseName, "_test.py") || strings.HasPrefix(baseName, "test_") {
211+
if matchesAnyGlob(baseName, testFileGlobs) {
199212
pyTestFilenames.Add(srcPath)
200213
} else {
201214
pyLibraryFilenames.Add(srcPath)
Lines changed: 19 additions & 0 deletions

gazelle/python/testdata/directive_python_test_file_pattern/WORKSPACE

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test.yaml

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# gazelle:python_generation_mode file
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
load("@rules_python//python:defs.bzl", "py_test")
2+
3+
# gazelle:python_generation_mode file
4+
5+
py_test(
6+
name = "hello_test",
7+
srcs = ["hello_test.py"],
8+
)
9+
10+
py_test(
11+
name = "test_goodbye",
12+
srcs = ["test_goodbye.py"],
13+
)
14+
15+
py_test(
16+
name = "test_hello",
17+
srcs = ["test_hello.py"],
18+
)

gazelle/python/testdata/directive_python_test_file_pattern/test1_unset/hello_test.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test1_unset/test_goodbye.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test1_unset/test_hello.py

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# gazelle:python_test_file_pattern *_test.py
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
load("@rules_python//python:defs.bzl", "py_library", "py_test")
2+
3+
# gazelle:python_test_file_pattern *_test.py
4+
5+
py_library(
6+
name = "test2_star_test_py",
7+
srcs = [
8+
"test_goodbye.py",
9+
"test_hello.py",
10+
],
11+
visibility = ["//:__subpackages__"],
12+
)
13+
14+
py_test(
15+
name = "hello_test",
16+
srcs = ["hello_test.py"],
17+
)

gazelle/python/testdata/directive_python_test_file_pattern/test2_star_test_py/hello_test.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test2_star_test_py/test_goodbye.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test2_star_test_py/test_hello.py

Whitespace-only changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# gazelle:python_generation_mode file
2+
# gazelle:python_test_file_pattern test_*.py
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
load("@rules_python//python:defs.bzl", "py_library", "py_test")
2+
3+
# gazelle:python_generation_mode file
4+
# gazelle:python_test_file_pattern test_*.py
5+
6+
py_library(
7+
name = "hello_test",
8+
srcs = ["hello_test.py"],
9+
visibility = ["//:__subpackages__"],
10+
)
11+
12+
py_test(
13+
name = "test_goodbye",
14+
srcs = ["test_goodbye.py"],
15+
)
16+
17+
py_test(
18+
name = "test_hello",
19+
srcs = ["test_hello.py"],
20+
)

gazelle/python/testdata/directive_python_test_file_pattern/test3_test_star_py/hello_test.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test3_test_star_py/test_goodbye.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test3_test_star_py/test_hello.py

Whitespace-only changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# gazelle:python_generation_mode file
2+
# gazelle:python_test_file_pattern foo_*_[A-Z]_test?.py
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
load("@rules_python//python:defs.bzl", "py_library", "py_test")
2+
3+
# gazelle:python_generation_mode file
4+
# gazelle:python_test_file_pattern foo_*_[A-Z]_test?.py
5+
6+
py_library(
7+
name = "foo_nota_test0_Z1",
8+
srcs = ["foo_nota_test0_Z1.py"],
9+
visibility = ["//:__subpackages__"],
10+
)
11+
12+
py_test(
13+
name = "foo_helloworld_A_testA",
14+
srcs = ["foo_helloworld_A_testA.py"],
15+
)
16+
17+
py_test(
18+
name = "foo_my_filename_B_test1",
19+
srcs = ["foo_my_filename_B_test1.py"],
20+
)

gazelle/python/testdata/directive_python_test_file_pattern/test4_glob/foo_helloworld_A_testA.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test4_glob/foo_my_filename_B_test1.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test4_glob/foo_nota_test0_Z1.py

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# gazelle:python_test_file_pattern *_hello.py,hello_*,unittest_*,*_unittest.py
2+
3+
# Note that "foo_unittest.pyc" and "test_bar" files are ignored.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
load("@rules_python//python:defs.bzl", "py_library", "py_test")
2+
3+
# gazelle:python_test_file_pattern *_hello.py,hello_*,unittest_*,*_unittest.py
4+
5+
# Note that "foo_unittest.pyc" and "test_bar" files are ignored.
6+
7+
py_library(
8+
name = "test5_multiple_patterns",
9+
srcs = [
10+
"mylib.py",
11+
"mylib2.py",
12+
],
13+
visibility = ["//:__subpackages__"],
14+
)
15+
16+
py_test(
17+
name = "foo_hello",
18+
srcs = ["foo_hello.py"],
19+
)
20+
21+
py_test(
22+
name = "foo_unittest",
23+
srcs = ["foo_unittest.py"],
24+
)
25+
26+
py_test(
27+
name = "hello_foo",
28+
srcs = ["hello_foo.py"],
29+
)
30+
31+
py_test(
32+
name = "unittest_foo",
33+
srcs = ["unittest_foo.py"],
34+
)

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/foo_hello.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/foo_unittest.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/foo_unittest.pyc

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/hello_foo.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/mylib.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/mylib2.py

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/test_bar

Whitespace-only changes.

gazelle/python/testdata/directive_python_test_file_pattern/test5_multiple_patterns/unittest_foo.py

Whitespace-only changes.

0 commit comments

Comments
 (0)