Resolving sibling modules with absolute imports (#1029)
* Resolving sibling modules with absolute imports
* unconditionally importing conftest
* handle from statements
* adding tests
* adding readme for the new test case
diff --git a/gazelle/python/generate.go b/gazelle/python/generate.go
index 4ebb40f..74e5f66 100644
--- a/gazelle/python/generate.go
+++ b/gazelle/python/generate.go
@@ -224,7 +224,6 @@
}
pyLibrary = newTargetBuilder(pyLibraryKind, pyLibraryTargetName, pythonProjectRoot, args.Rel, pyLibraryFilenames.Union(pyTestFilenames)).
- setUUID(label.New("", args.Rel, pyLibraryTargetName).String()).
addVisibility(visibility).
addSrcs(pyLibraryFilenames).
addModuleDependencies(deps).
@@ -267,10 +266,6 @@
addModuleDependencies(deps).
generateImportsAttribute()
- if pyLibrary != nil {
- pyBinaryTarget.addModuleDependency(module{Name: pyLibrary.PrivateAttr(uuidKey).(string)})
- }
-
pyBinary := pyBinaryTarget.build()
result.Gen = append(result.Gen, pyBinary)
@@ -301,7 +296,6 @@
}
conftestTarget := newTargetBuilder(pyLibraryKind, conftestTargetname, pythonProjectRoot, args.Rel, pyLibraryFilenames.Union(pyTestFilenames)).
- setUUID(label.New("", args.Rel, conftestTargetname).String()).
addSrc(conftestFilename).
addModuleDependencies(deps).
addVisibility(visibility).
@@ -315,8 +309,8 @@
}
var pyTestTargets []*targetBuilder
- newPyTestTargetBuilder := func(pyTestFilenames *treeset.Set, pyTestTargetName string) *targetBuilder {
- deps, err := parser.parse(pyTestFilenames)
+ newPyTestTargetBuilder := func(srcs *treeset.Set, pyTestTargetName string) *targetBuilder {
+ deps, err := parser.parse(srcs)
if err != nil {
log.Fatalf("ERROR: %v\n", err)
}
@@ -337,7 +331,7 @@
}
}
return newTargetBuilder(pyTestKind, pyTestTargetName, pythonProjectRoot, args.Rel, pyLibraryFilenames.Union(pyTestFilenames)).
- addSrcs(pyTestFilenames).
+ addSrcs(srcs).
addModuleDependencies(deps).
generateImportsAttribute()
}
@@ -371,14 +365,9 @@
}
for _, pyTestTarget := range pyTestTargets {
- if pyLibrary != nil {
- pyTestTarget.addModuleDependency(module{Name: pyLibrary.PrivateAttr(uuidKey).(string)})
- }
-
if conftest != nil {
- pyTestTarget.addModuleDependency(module{Name: conftest.PrivateAttr(uuidKey).(string)})
+ pyTestTarget.addModuleDependency(module{Name: strings.TrimSuffix(conftestFilename, ".py")})
}
-
pyTest := pyTestTarget.build()
result.Gen = append(result.Gen, pyTest)
diff --git a/gazelle/python/resolve.go b/gazelle/python/resolve.go
index 607776a..46014e5 100644
--- a/gazelle/python/resolve.go
+++ b/gazelle/python/resolve.go
@@ -39,10 +39,6 @@
// resolvedDepsKey is the attribute key used to pass dependencies that don't
// need to be resolved by the dependency resolver in the Resolver step.
resolvedDepsKey = "_gazelle_python_resolved_deps"
- // uuidKey is the attribute key used to uniquely identify a py_library
- // target that should be imported by a py_test or py_binary in the same
- // Bazel package.
- uuidKey = "_gazelle_python_library_uuid"
)
// Resolver satisfies the resolve.Resolver interface. It resolves dependencies
@@ -71,13 +67,6 @@
provides = append(provides, provide)
}
}
- if r.PrivateAttr(uuidKey) != nil {
- provide := resolve.ImportSpec{
- Lang: languageName,
- Imp: r.PrivateAttr(uuidKey).(string),
- }
- provides = append(provides, provide)
- }
if len(provides) == 0 {
return nil
}
diff --git a/gazelle/python/target.go b/gazelle/python/target.go
index 69711ce..fdc99fc 100644
--- a/gazelle/python/target.go
+++ b/gazelle/python/target.go
@@ -15,12 +15,11 @@
package python
import (
- "path/filepath"
-
"github.com/bazelbuild/bazel-gazelle/config"
"github.com/bazelbuild/bazel-gazelle/rule"
"github.com/emirpasic/gods/sets/treeset"
godsutils "github.com/emirpasic/gods/utils"
+ "path/filepath"
)
// targetBuilder builds targets to be generated by Gazelle.
@@ -29,7 +28,6 @@
name string
pythonProjectRoot string
bzlPackage string
- uuid string
srcs *treeset.Set
siblingSrcs *treeset.Set
deps *treeset.Set
@@ -55,15 +53,6 @@
}
}
-// setUUID sets the given UUID for the target. It's used to index the generated
-// target based on this value in addition to the other ways the targets can be
-// imported. py_{binary,test} targets in the same Bazel package can add a
-// virtual dependency to this UUID that gets resolved in the Resolver interface.
-func (t *targetBuilder) setUUID(uuid string) *targetBuilder {
- t.uuid = uuid
- return t
-}
-
// addSrc adds a single src to the target.
func (t *targetBuilder) addSrc(src string) *targetBuilder {
t.srcs.Add(src)
@@ -81,9 +70,16 @@
// addModuleDependency adds a single module dep to the target.
func (t *targetBuilder) addModuleDependency(dep module) *targetBuilder {
- if dep.Name+".py" == filepath.Base(dep.Filepath) || !t.siblingSrcs.Contains(dep.Name+".py") {
- t.deps.Add(dep)
+ fileName := dep.Name + ".py"
+ if dep.From != "" {
+ fileName = dep.From + ".py"
}
+ if t.siblingSrcs.Contains(fileName) && fileName != filepath.Base(dep.Filepath) {
+ // importing another module from the same package, converting to absolute imports to make
+ // dependency resolution easier
+ dep.Name = importSpecFromSrc(t.pythonProjectRoot, t.bzlPackage, fileName).Imp
+ }
+ t.deps.Add(dep)
return t
}
@@ -138,9 +134,6 @@
// build returns the assembled *rule.Rule for the target.
func (t *targetBuilder) build() *rule.Rule {
r := rule.NewRule(t.kind, t.name)
- if t.uuid != "" {
- r.SetPrivateAttr(uuidKey, t.uuid)
- }
if !t.srcs.Empty() {
r.SetAttr("srcs", t.srcs.Values())
}
diff --git a/gazelle/python/testdata/generated_test_entrypoint/BUILD.out b/gazelle/python/testdata/generated_test_entrypoint/BUILD.out
index 48df068..e8e304c 100644
--- a/gazelle/python/testdata/generated_test_entrypoint/BUILD.out
+++ b/gazelle/python/testdata/generated_test_entrypoint/BUILD.out
@@ -17,8 +17,5 @@
name = "generated_test_entrypoint_test",
srcs = [":__test__"],
main = ":__test__.py",
- deps = [
- ":__test__",
- ":generated_test_entrypoint",
- ],
+ deps = [":__test__"],
)
diff --git a/gazelle/python/testdata/naming_convention/__main__.py b/gazelle/python/testdata/naming_convention/__main__.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/naming_convention/__main__.py
+++ b/gazelle/python/testdata/naming_convention/__main__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/naming_convention/__test__.py b/gazelle/python/testdata/naming_convention/__test__.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/naming_convention/__test__.py
+++ b/gazelle/python/testdata/naming_convention/__test__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/naming_convention/dont_rename/__main__.py b/gazelle/python/testdata/naming_convention/dont_rename/__main__.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/naming_convention/dont_rename/__main__.py
+++ b/gazelle/python/testdata/naming_convention/dont_rename/__main__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/naming_convention/dont_rename/__test__.py b/gazelle/python/testdata/naming_convention/dont_rename/__test__.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/naming_convention/dont_rename/__test__.py
+++ b/gazelle/python/testdata/naming_convention/dont_rename/__test__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/naming_convention/resolve_conflict/__main__.py b/gazelle/python/testdata/naming_convention/resolve_conflict/__main__.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/naming_convention/resolve_conflict/__main__.py
+++ b/gazelle/python/testdata/naming_convention/resolve_conflict/__main__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/naming_convention/resolve_conflict/__test__.py b/gazelle/python/testdata/naming_convention/resolve_conflict/__test__.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/naming_convention/resolve_conflict/__test__.py
+++ b/gazelle/python/testdata/naming_convention/resolve_conflict/__test__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/python_target_with_test_in_name/real_test.py b/gazelle/python/testdata/python_target_with_test_in_name/real_test.py
index 2f03211..e390866 100644
--- a/gazelle/python/testdata/python_target_with_test_in_name/real_test.py
+++ b/gazelle/python/testdata/python_target_with_test_in_name/real_test.py
@@ -13,5 +13,6 @@
# limitations under the License.
import boto3
+import __init__
_ = boto3
diff --git a/gazelle/python/testdata/python_target_with_test_in_name/test_reality.py b/gazelle/python/testdata/python_target_with_test_in_name/test_reality.py
index 7307559..a3afc79 100644
--- a/gazelle/python/testdata/python_target_with_test_in_name/test_reality.py
+++ b/gazelle/python/testdata/python_target_with_test_in_name/test_reality.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import __init__
\ No newline at end of file
diff --git a/gazelle/python/testdata/sibling_imports/README.md b/gazelle/python/testdata/sibling_imports/README.md
new file mode 100644
index 0000000..e59be07
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/README.md
@@ -0,0 +1,3 @@
+# Sibling imports
+
+This test case asserts that imports from sibling modules are resolved correctly. It covers 3 different types of imports in `pkg/unit_test.py`
\ No newline at end of file
diff --git a/gazelle/python/testdata/sibling_imports/WORKSPACE b/gazelle/python/testdata/sibling_imports/WORKSPACE
new file mode 100644
index 0000000..faff6af
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/WORKSPACE
@@ -0,0 +1 @@
+# This is a Bazel workspace for the Gazelle test data.
diff --git a/gazelle/python/testdata/sibling_imports/pkg/BUILD.in b/gazelle/python/testdata/sibling_imports/pkg/BUILD.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/BUILD.in
diff --git a/gazelle/python/testdata/sibling_imports/pkg/BUILD.out b/gazelle/python/testdata/sibling_imports/pkg/BUILD.out
new file mode 100644
index 0000000..edb40a8
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/BUILD.out
@@ -0,0 +1,29 @@
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
+
+py_library(
+ name = "pkg",
+ srcs = [
+ "__init__.py",
+ "a.py",
+ "b.py",
+ ],
+ imports = [".."],
+ visibility = ["//:__subpackages__"],
+)
+
+py_test(
+ name = "test_util",
+ srcs = ["test_util.py"],
+ imports = [".."],
+)
+
+py_test(
+ name = "unit_test",
+ srcs = ["unit_test.py"],
+ imports = [".."],
+ deps = [
+ ":pkg",
+ ":test_util",
+ ],
+)
+
diff --git a/gazelle/python/testdata/sibling_imports/pkg/__init__.py b/gazelle/python/testdata/sibling_imports/pkg/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/__init__.py
diff --git a/gazelle/python/testdata/sibling_imports/pkg/a.py b/gazelle/python/testdata/sibling_imports/pkg/a.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/a.py
diff --git a/gazelle/python/testdata/sibling_imports/pkg/b.py b/gazelle/python/testdata/sibling_imports/pkg/b.py
new file mode 100644
index 0000000..7095bdc
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/b.py
@@ -0,0 +1,2 @@
+def run():
+ pass
\ No newline at end of file
diff --git a/gazelle/python/testdata/sibling_imports/pkg/test_util.py b/gazelle/python/testdata/sibling_imports/pkg/test_util.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/test_util.py
diff --git a/gazelle/python/testdata/sibling_imports/pkg/unit_test.py b/gazelle/python/testdata/sibling_imports/pkg/unit_test.py
new file mode 100644
index 0000000..a3218e2
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/pkg/unit_test.py
@@ -0,0 +1,3 @@
+import a
+from b import run
+import test_util
\ No newline at end of file
diff --git a/gazelle/python/testdata/sibling_imports/test.yaml b/gazelle/python/testdata/sibling_imports/test.yaml
new file mode 100644
index 0000000..ed97d53
--- /dev/null
+++ b/gazelle/python/testdata/sibling_imports/test.yaml
@@ -0,0 +1 @@
+---
diff --git a/gazelle/python/testdata/simple_binary_with_library/__main__.py b/gazelle/python/testdata/simple_binary_with_library/__main__.py
index 7307559..bc7ddf0 100644
--- a/gazelle/python/testdata/simple_binary_with_library/__main__.py
+++ b/gazelle/python/testdata/simple_binary_with_library/__main__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import foo
diff --git a/gazelle/python/testdata/subdir_sources/foo/has_main/__main__.py b/gazelle/python/testdata/subdir_sources/foo/has_main/__main__.py
index 7307559..bd0fe61 100644
--- a/gazelle/python/testdata/subdir_sources/foo/has_main/__main__.py
+++ b/gazelle/python/testdata/subdir_sources/foo/has_main/__main__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import foo.has_main.python.my_module
\ No newline at end of file
diff --git a/gazelle/python/testdata/subdir_sources/foo/has_test/__test__.py b/gazelle/python/testdata/subdir_sources/foo/has_test/__test__.py
index 7307559..3c9ed1a 100644
--- a/gazelle/python/testdata/subdir_sources/foo/has_test/__test__.py
+++ b/gazelle/python/testdata/subdir_sources/foo/has_test/__test__.py
@@ -13,3 +13,4 @@
# limitations under the License.
# For test purposes only.
+import foo.has_test.python.my_module
\ No newline at end of file
diff --git a/gazelle/python/testdata/with_third_party_requirements/BUILD.out b/gazelle/python/testdata/with_third_party_requirements/BUILD.out
index 2da7f2b..2a97d8b 100644
--- a/gazelle/python/testdata/with_third_party_requirements/BUILD.out
+++ b/gazelle/python/testdata/with_third_party_requirements/BUILD.out
@@ -20,5 +20,5 @@
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
- deps = [":with_third_party_requirements"],
+ deps = ["@gazelle_python_test_baz//:pkg"],
)