From 813400547a5f85965fb68faca17b0dd95e8e6746 Mon Sep 17 00:00:00 2001 From: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> Date: Wed, 9 Nov 2022 11:17:37 -0800 Subject: [PATCH 1/4] fix: add conftest.py to py_test generated targets Signed-off-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> --- gazelle/generate.go | 2 +- .../simple_test_with_conftest/BUILD.in | 6 ++++++ .../simple_test_with_conftest/BUILD.out | 20 +++++++++++++++++++ .../simple_test_with_conftest/README.md | 4 ++++ .../simple_test_with_conftest/WORKSPACE | 1 + .../simple_test_with_conftest/__init__.py | 3 +++ .../simple_test_with_conftest/__test__.py | 12 +++++++++++ .../simple_test_with_conftest/conftest.py | 0 .../testdata/simple_test_with_conftest/foo.py | 2 ++ .../simple_test_with_conftest/test.yaml | 3 +++ 10 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 gazelle/testdata/simple_test_with_conftest/BUILD.in create mode 100644 gazelle/testdata/simple_test_with_conftest/BUILD.out create mode 100644 gazelle/testdata/simple_test_with_conftest/README.md create mode 100644 gazelle/testdata/simple_test_with_conftest/WORKSPACE create mode 100644 gazelle/testdata/simple_test_with_conftest/__init__.py create mode 100644 gazelle/testdata/simple_test_with_conftest/__test__.py create mode 100644 gazelle/testdata/simple_test_with_conftest/conftest.py create mode 100644 gazelle/testdata/simple_test_with_conftest/foo.py create mode 100644 gazelle/testdata/simple_test_with_conftest/test.yaml diff --git a/gazelle/generate.go b/gazelle/generate.go index 077acb821a..00e934ddae 100644 --- a/gazelle/generate.go +++ b/gazelle/generate.go @@ -81,7 +81,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes hasPyBinary = true } else if !hasPyTestFile && f == pyTestEntrypointFilename { hasPyTestFile = true - } else if strings.HasSuffix(f, "_test.py") || (strings.HasPrefix(f, "test_") && ext == ".py") { + } else if f == "conftest.py" || strings.HasSuffix(f, "_test.py") || (strings.HasPrefix(f, "test_") && ext == ".py") { pyTestFilenames.Add(f) } else if ext == ".py" { pyLibraryFilenames.Add(f) diff --git a/gazelle/testdata/simple_test_with_conftest/BUILD.in b/gazelle/testdata/simple_test_with_conftest/BUILD.in new file mode 100644 index 0000000000..6b817db9aa --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/BUILD.in @@ -0,0 +1,6 @@ +load("@rules_python//python:defs.bzl", "py_library") + +py_library( + name = "simple_test_with_conftest", + srcs = ["__init__.py"], +) diff --git a/gazelle/testdata/simple_test_with_conftest/BUILD.out b/gazelle/testdata/simple_test_with_conftest/BUILD.out new file mode 100644 index 0000000000..d73bb79a26 --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/BUILD.out @@ -0,0 +1,20 @@ +load("@rules_python//python:defs.bzl", "py_library", "py_test") + +py_library( + name = "simple_test_with_conftest", + srcs = [ + "__init__.py", + "foo.py", + ], + visibility = ["//:__subpackages__"], +) + +py_test( + name = "simple_test_with_conftest_test", + srcs = [ + "__test__.py", + "conftest.py", + ], + main = "__test__.py", + deps = [":simple_test_with_conftest"], +) diff --git a/gazelle/testdata/simple_test_with_conftest/README.md b/gazelle/testdata/simple_test_with_conftest/README.md new file mode 100644 index 0000000000..0ff245f808 --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/README.md @@ -0,0 +1,4 @@ +# Simple test with conftest.py + +This test case asserts that a simple `py_test` is generated as expected when a +`conftest.py` is present. diff --git a/gazelle/testdata/simple_test_with_conftest/WORKSPACE b/gazelle/testdata/simple_test_with_conftest/WORKSPACE new file mode 100644 index 0000000000..faff6af87a --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/WORKSPACE @@ -0,0 +1 @@ +# This is a Bazel workspace for the Gazelle test data. diff --git a/gazelle/testdata/simple_test_with_conftest/__init__.py b/gazelle/testdata/simple_test_with_conftest/__init__.py new file mode 100644 index 0000000000..6a49193fe4 --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/__init__.py @@ -0,0 +1,3 @@ +from foo import foo + +_ = foo diff --git a/gazelle/testdata/simple_test_with_conftest/__test__.py b/gazelle/testdata/simple_test_with_conftest/__test__.py new file mode 100644 index 0000000000..d6085a41b4 --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/__test__.py @@ -0,0 +1,12 @@ +import unittest + +from __init__ import foo + + +class FooTest(unittest.TestCase): + def test_foo(self): + self.assertEqual("foo", foo()) + + +if __name__ == "__main__": + unittest.main() diff --git a/gazelle/testdata/simple_test_with_conftest/conftest.py b/gazelle/testdata/simple_test_with_conftest/conftest.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gazelle/testdata/simple_test_with_conftest/foo.py b/gazelle/testdata/simple_test_with_conftest/foo.py new file mode 100644 index 0000000000..cf68624419 --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/foo.py @@ -0,0 +1,2 @@ +def foo(): + return "foo" diff --git a/gazelle/testdata/simple_test_with_conftest/test.yaml b/gazelle/testdata/simple_test_with_conftest/test.yaml new file mode 100644 index 0000000000..36dd656b39 --- /dev/null +++ b/gazelle/testdata/simple_test_with_conftest/test.yaml @@ -0,0 +1,3 @@ +--- +expect: + exit_code: 0 From bf6d3b7f989a813f5263f22e268e88abf0654484 Mon Sep 17 00:00:00 2001 From: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> Date: Wed, 9 Nov 2022 15:41:19 -0800 Subject: [PATCH 2/4] fix: use separate py_library for conftest.py This allows the conftest.py to be used on sub-directories as pytest would pick them up. Signed-off-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> --- gazelle/generate.go | 71 +++++++++++++++---- .../simple_test_with_conftest/BUILD.in | 5 -- .../simple_test_with_conftest/BUILD.out | 16 +++-- 3 files changed, 69 insertions(+), 23 deletions(-) diff --git a/gazelle/generate.go b/gazelle/generate.go index 00e934ddae..8def4bc15b 100644 --- a/gazelle/generate.go +++ b/gazelle/generate.go @@ -26,6 +26,8 @@ const ( pyBinaryEntrypointFilename = "__main__.py" pyTestEntrypointFilename = "__test__.py" pyTestEntrypointTargetname = "__test__" + conftestFilename = "conftest.py" + conftestTargetname = "conftest" ) var ( @@ -71,6 +73,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes // be generated for this package or not. hasPyTestFile := false hasPyTestTarget := false + hasConftestFile := false for _, f := range args.RegularFiles { if cfg.IgnoresFile(filepath.Base(f)) { @@ -81,7 +84,9 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes hasPyBinary = true } else if !hasPyTestFile && f == pyTestEntrypointFilename { hasPyTestFile = true - } else if f == "conftest.py" || strings.HasSuffix(f, "_test.py") || (strings.HasPrefix(f, "test_") && ext == ".py") { + } else if f == conftestFilename { + hasConftestFile = true + } else if strings.HasSuffix(f, "_test.py") || (strings.HasPrefix(f, "test_") && ext == ".py") { pyTestFilenames.Add(f) } else if ext == ".py" { pyLibraryFilenames.Add(f) @@ -196,10 +201,10 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes pyLibraryTargetName := cfg.RenderLibraryName(packageName) - // Check if a target with the same name we are generating alredy 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. + // 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 args.File != nil { for _, t := range args.File.Rules { if t.Name() == pyLibraryTargetName && t.Kind() != pyLibraryKind { @@ -233,10 +238,10 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes pyBinaryTargetName := cfg.RenderBinaryName(packageName) - // Check if a target with the same name we are generating alredy 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. + // 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 args.File != nil { for _, t := range args.File.Rules { if t.Name() == pyBinaryTargetName && t.Kind() != pyBinaryKind { @@ -267,6 +272,42 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes result.Imports = append(result.Imports, pyBinary.PrivateAttr(config.GazelleImportsKey)) } + var conftest *rule.Rule + if hasConftestFile { + deps, err := parser.parseSingle(conftestFilename) + if err != nil { + 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 args.File != nil { + for _, t := range args.File.Rules { + if t.Name() == conftestTargetname && t.Kind() != pyLibraryKind { + fqTarget := label.New("", args.Rel, conftestTargetname) + err := fmt.Errorf("failed to generate target %q of kind %q: "+ + "a target of kind %q with the same name already exists.", + fqTarget.String(), pyLibraryKind, t.Kind()) + collisionErrors.Add(err) + } + } + } + + conftestTarget := newTargetBuilder(pyLibraryKind, conftestTargetname, pythonProjectRoot, args.Rel). + setUUID(uuid.Must(uuid.NewUUID()).String()). + addSrc(conftestFilename). + addModuleDependencies(deps). + addVisibility(visibility). + generateImportsAttribute() + + conftest = conftestTarget.build() + + result.Gen = append(result.Gen, conftest) + result.Imports = append(result.Imports, conftest.PrivateAttr(config.GazelleImportsKey)) + } + if hasPyTestFile || hasPyTestTarget { if hasPyTestFile { // Only add the pyTestEntrypointFilename to the pyTestFilenames if @@ -280,10 +321,10 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes pyTestTargetName := cfg.RenderTestName(packageName) - // Check if a target with the same name we are generating alredy 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. + // 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 args.File != nil { for _, t := range args.File.Rules { if t.Name() == pyTestTargetName && t.Kind() != pyTestKind { @@ -317,6 +358,10 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes pyTestTarget.addModuleDependency(module{Name: pyLibrary.PrivateAttr(uuidKey).(string)}) } + if conftest != nil { + pyTestTarget.addModuleDependency(module{Name: conftest.PrivateAttr(uuidKey).(string)}) + } + pyTest := pyTestTarget.build() result.Gen = append(result.Gen, pyTest) diff --git a/gazelle/testdata/simple_test_with_conftest/BUILD.in b/gazelle/testdata/simple_test_with_conftest/BUILD.in index 6b817db9aa..3f2beb3147 100644 --- a/gazelle/testdata/simple_test_with_conftest/BUILD.in +++ b/gazelle/testdata/simple_test_with_conftest/BUILD.in @@ -1,6 +1 @@ load("@rules_python//python:defs.bzl", "py_library") - -py_library( - name = "simple_test_with_conftest", - srcs = ["__init__.py"], -) diff --git a/gazelle/testdata/simple_test_with_conftest/BUILD.out b/gazelle/testdata/simple_test_with_conftest/BUILD.out index d73bb79a26..641c379e09 100644 --- a/gazelle/testdata/simple_test_with_conftest/BUILD.out +++ b/gazelle/testdata/simple_test_with_conftest/BUILD.out @@ -9,12 +9,18 @@ py_library( visibility = ["//:__subpackages__"], ) +py_library( + name = "conftest", + srcs = ["conftest.py"], + visibility = ["//:__subpackages__"], +) + py_test( name = "simple_test_with_conftest_test", - srcs = [ - "__test__.py", - "conftest.py", - ], + srcs = ["__test__.py"], main = "__test__.py", - deps = [":simple_test_with_conftest"], + deps = [ + ":conftest", + ":simple_test_with_conftest", + ], ) From 39b306cf1491ee4ad3918b6c4116400b74fadf63 Mon Sep 17 00:00:00 2001 From: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> Date: Wed, 9 Nov 2022 15:52:33 -0800 Subject: [PATCH 3/4] fix: add testonly to conftest py_library Signed-off-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> --- gazelle/generate.go | 1 + gazelle/target.go | 10 ++++++++++ gazelle/testdata/simple_test_with_conftest/BUILD.out | 1 + 3 files changed, 12 insertions(+) diff --git a/gazelle/generate.go b/gazelle/generate.go index 8def4bc15b..c7b0709687 100644 --- a/gazelle/generate.go +++ b/gazelle/generate.go @@ -300,6 +300,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes addSrc(conftestFilename). addModuleDependencies(deps). addVisibility(visibility). + setTestonly(). generateImportsAttribute() conftest = conftestTarget.build() diff --git a/gazelle/target.go b/gazelle/target.go index 2b260679b6..29428e140a 100644 --- a/gazelle/target.go +++ b/gazelle/target.go @@ -22,6 +22,7 @@ type targetBuilder struct { visibility *treeset.Set main *string imports []string + testonly bool } // newTargetBuilder constructs a new targetBuilder. @@ -96,6 +97,12 @@ func (t *targetBuilder) setMain(main string) *targetBuilder { return t } +// setTestonly sets the testonly attribute to true. +func (t *targetBuilder) setTestonly() *targetBuilder { + t.testonly = true + return t +} + // generateImportsAttribute generates the imports attribute. // These are a list of import directories to be added to the PYTHONPATH. In our // case, the value we add is on Bazel sub-packages to be able to perform imports @@ -131,6 +138,9 @@ func (t *targetBuilder) build() *rule.Rule { if !t.deps.Empty() { r.SetPrivateAttr(config.GazelleImportsKey, t.deps) } + if t.testonly { + r.SetAttr("testonly", "True") + } r.SetPrivateAttr(resolvedDepsKey, t.resolvedDeps) return r } diff --git a/gazelle/testdata/simple_test_with_conftest/BUILD.out b/gazelle/testdata/simple_test_with_conftest/BUILD.out index 641c379e09..d5f1e9ce72 100644 --- a/gazelle/testdata/simple_test_with_conftest/BUILD.out +++ b/gazelle/testdata/simple_test_with_conftest/BUILD.out @@ -11,6 +11,7 @@ py_library( py_library( name = "conftest", + testonly = "True", srcs = ["conftest.py"], visibility = ["//:__subpackages__"], ) From 746459a3084d7a068094d52c58d49d6acdc8c95d Mon Sep 17 00:00:00 2001 From: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> Date: Thu, 10 Nov 2022 10:30:20 -0800 Subject: [PATCH 4/4] fix: testonly is a boolean, not a string Signed-off-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> --- gazelle/target.go | 2 +- gazelle/testdata/simple_test_with_conftest/BUILD.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gazelle/target.go b/gazelle/target.go index 29428e140a..eef3aedd8d 100644 --- a/gazelle/target.go +++ b/gazelle/target.go @@ -139,7 +139,7 @@ func (t *targetBuilder) build() *rule.Rule { r.SetPrivateAttr(config.GazelleImportsKey, t.deps) } if t.testonly { - r.SetAttr("testonly", "True") + r.SetAttr("testonly", true) } r.SetPrivateAttr(resolvedDepsKey, t.resolvedDeps) return r diff --git a/gazelle/testdata/simple_test_with_conftest/BUILD.out b/gazelle/testdata/simple_test_with_conftest/BUILD.out index d5f1e9ce72..18079bf2f4 100644 --- a/gazelle/testdata/simple_test_with_conftest/BUILD.out +++ b/gazelle/testdata/simple_test_with_conftest/BUILD.out @@ -11,7 +11,7 @@ py_library( py_library( name = "conftest", - testonly = "True", + testonly = True, srcs = ["conftest.py"], visibility = ["//:__subpackages__"], )