Skip to content

Commit dc1dbf1

Browse files
committed
feat(gazelle) Allow disabling sibling module resolution
1 parent f02c9c7 commit dc1dbf1

File tree

20 files changed

+145
-34
lines changed

20 files changed

+145
-34
lines changed

gazelle/python/configure.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func (py *Configurer) KnownDirectives() []string {
7171
pythonconfig.GeneratePyiDeps,
7272
pythonconfig.ExperimentalAllowRelativeImports,
7373
pythonconfig.GenerateProto,
74+
pythonconfig.PythonResolveSiblingImports,
7475
}
7576
}
7677

@@ -244,6 +245,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
244245
log.Fatal(err)
245246
}
246247
config.SetGenerateProto(v)
248+
case pythonconfig.PythonResolveSiblingImports:
249+
v, err := strconv.ParseBool(strings.TrimSpace(d.Value))
250+
if err != nil {
251+
log.Fatal(err)
252+
}
253+
config.SetResolveSiblingImports(v)
247254
}
248255
}
249256

gazelle/python/generate.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
259259
fqTarget.String(), actualPyBinaryKind, err)
260260
continue
261261
}
262-
pyBinary := newTargetBuilder(pyBinaryKind, pyBinaryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
262+
pyBinary := newTargetBuilder(pyBinaryKind, pyBinaryTargetName, pythonProjectRoot, args.Rel, pyFileNames, cfg.ResolveSiblingImports()).
263263
addVisibility(visibility).
264264
addSrc(filename).
265265
addModuleDependencies(mainModules[filename]).
@@ -301,7 +301,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
301301
collisionErrors.Add(err)
302302
}
303303

304-
pyLibrary := newTargetBuilder(pyLibraryKind, pyLibraryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
304+
pyLibrary := newTargetBuilder(pyLibraryKind, pyLibraryTargetName, pythonProjectRoot, args.Rel, pyFileNames, cfg.ResolveSiblingImports()).
305305
addVisibility(visibility).
306306
addSrcs(srcs).
307307
addModuleDependencies(allDeps).
@@ -354,7 +354,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
354354
collisionErrors.Add(err)
355355
}
356356

357-
pyBinaryTarget := newTargetBuilder(pyBinaryKind, pyBinaryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
357+
pyBinaryTarget := newTargetBuilder(pyBinaryKind, pyBinaryTargetName, pythonProjectRoot, args.Rel, pyFileNames, cfg.ResolveSiblingImports()).
358358
setMain(pyBinaryEntrypointFilename).
359359
addVisibility(visibility).
360360
addSrc(pyBinaryEntrypointFilename).
@@ -387,7 +387,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
387387
collisionErrors.Add(err)
388388
}
389389

390-
conftestTarget := newTargetBuilder(pyLibraryKind, conftestTargetname, pythonProjectRoot, args.Rel, pyFileNames).
390+
conftestTarget := newTargetBuilder(pyLibraryKind, conftestTargetname, pythonProjectRoot, args.Rel, pyFileNames, cfg.ResolveSiblingImports()).
391391
addSrc(conftestFilename).
392392
addModuleDependencies(deps).
393393
addResolvedDependencies(annotations.includeDeps).
@@ -419,7 +419,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
419419
fqTarget.String(), actualPyTestKind, err, pythonconfig.TestNamingConvention)
420420
collisionErrors.Add(err)
421421
}
422-
return newTargetBuilder(pyTestKind, pyTestTargetName, pythonProjectRoot, args.Rel, pyFileNames).
422+
return newTargetBuilder(pyTestKind, pyTestTargetName, pythonProjectRoot, args.Rel, pyFileNames, cfg.ResolveSiblingImports()).
423423
addSrcs(srcs).
424424
addModuleDependencies(deps).
425425
addResolvedDependencies(annotations.includeDeps).
@@ -594,7 +594,7 @@ func generateProtoLibraries(args language.GenerateArgs, pythonProjectRoot string
594594
// Generate a py_proto_library for each proto_library.
595595
for _, protoRuleName := range protoRuleNames {
596596
pyProtoLibraryName := strings.TrimSuffix(protoRuleName, "_proto") + "_py_pb2"
597-
pyProtoLibrary := newTargetBuilder(pyProtoLibraryKind, pyProtoLibraryName, pythonProjectRoot, args.Rel, &emptySiblings).
597+
pyProtoLibrary := newTargetBuilder(pyProtoLibraryKind, pyProtoLibraryName, pythonProjectRoot, args.Rel, &emptySiblings, false).
598598
addVisibility(visibility).
599599
addResolvedDependency(":" + protoRuleName).
600600
generateImportsAttribute().build()
@@ -611,7 +611,7 @@ func generateProtoLibraries(args language.GenerateArgs, pythonProjectRoot string
611611
continue
612612
}
613613

614-
emptyRule := newTargetBuilder(pyProtoLibraryKind, ruleName, pythonProjectRoot, args.Rel, &emptySiblings).build()
614+
emptyRule := newTargetBuilder(pyProtoLibraryKind, ruleName, pythonProjectRoot, args.Rel, &emptySiblings, false).build()
615615
res.Empty = append(res.Empty, emptyRule)
616616
}
617617

gazelle/python/target.go

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,34 +25,36 @@ import (
2525

2626
// targetBuilder builds targets to be generated by Gazelle.
2727
type targetBuilder struct {
28-
kind string
29-
name string
30-
pythonProjectRoot string
31-
bzlPackage string
32-
srcs *treeset.Set
33-
siblingSrcs *treeset.Set
34-
deps *treeset.Set
35-
resolvedDeps *treeset.Set
36-
visibility *treeset.Set
37-
main *string
38-
imports []string
39-
testonly bool
40-
annotations *annotations
28+
kind string
29+
name string
30+
pythonProjectRoot string
31+
bzlPackage string
32+
srcs *treeset.Set
33+
siblingSrcs *treeset.Set
34+
deps *treeset.Set
35+
resolvedDeps *treeset.Set
36+
visibility *treeset.Set
37+
main *string
38+
imports []string
39+
testonly bool
40+
annotations *annotations
41+
resolveSiblingImports bool
4142
}
4243

4344
// newTargetBuilder constructs a new targetBuilder.
44-
func newTargetBuilder(kind, name, pythonProjectRoot, bzlPackage string, siblingSrcs *treeset.Set) *targetBuilder {
45+
func newTargetBuilder(kind, name, pythonProjectRoot, bzlPackage string, siblingSrcs *treeset.Set, resolveSiblingImports bool) *targetBuilder {
4546
return &targetBuilder{
46-
kind: kind,
47-
name: name,
48-
pythonProjectRoot: pythonProjectRoot,
49-
bzlPackage: bzlPackage,
50-
srcs: treeset.NewWith(godsutils.StringComparator),
51-
siblingSrcs: siblingSrcs,
52-
deps: treeset.NewWith(moduleComparator),
53-
resolvedDeps: treeset.NewWith(godsutils.StringComparator),
54-
visibility: treeset.NewWith(godsutils.StringComparator),
55-
annotations: new(annotations),
47+
kind: kind,
48+
name: name,
49+
pythonProjectRoot: pythonProjectRoot,
50+
bzlPackage: bzlPackage,
51+
srcs: treeset.NewWith(godsutils.StringComparator),
52+
siblingSrcs: siblingSrcs,
53+
deps: treeset.NewWith(moduleComparator),
54+
resolvedDeps: treeset.NewWith(godsutils.StringComparator),
55+
visibility: treeset.NewWith(godsutils.StringComparator),
56+
annotations: new(annotations),
57+
resolveSiblingImports: resolveSiblingImports,
5658
}
5759
}
5860

@@ -77,7 +79,7 @@ func (t *targetBuilder) addModuleDependency(dep Module) *targetBuilder {
7779
if dep.From != "" {
7880
fileName = dep.From + ".py"
7981
}
80-
if t.siblingSrcs.Contains(fileName) && fileName != filepath.Base(dep.Filepath) {
82+
if t.resolveSiblingImports && t.siblingSrcs.Contains(fileName) && fileName != filepath.Base(dep.Filepath) {
8183
// importing another module from the same package, converting to absolute imports to make
8284
// dependency resolution easier
8385
dep.Name = importSpecFromSrc(t.pythonProjectRoot, t.bzlPackage, fileName).Imp
@@ -138,7 +140,6 @@ func (t *targetBuilder) setAnnotations(val annotations) *targetBuilder {
138140
return t
139141
}
140142

141-
142143
// generateImportsAttribute generates the imports attribute.
143144
// These are a list of import directories to be added to the PYTHONPATH. In our
144145
// case, the value we add is on Bazel sub-packages to be able to perform imports
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
# Sibling imports
22

3-
This test case asserts that imports from sibling modules are resolved correctly. It covers 3 different types of imports in `pkg/unit_test.py`
3+
This test case asserts that imports from sibling modules are resolved correctly
4+
when the `python_resolve_sibling_imports` directive is enabled (default
5+
behavior). It covers 3 different types of imports in `pkg/unit_test.py`:
6+
7+
- `import a` - resolves to the sibling `a.py` in the same package
8+
- `import test_util` - resolves to the sibling `test_util.py` in the same
9+
package
10+
- `from b import run` - resolves to the sibling `b.py` in the same package
11+
12+
When sibling imports are enabled, we allow them to be satisfied by sibling
13+
modules (ie. modules in the same package).
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# gazelle:python_resolve_sibling_imports false
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_resolve_sibling_imports false
4+
5+
py_library(
6+
name = "sibling_imports_disabled",
7+
srcs = [
8+
"a.py",
9+
"b.py",
10+
],
11+
visibility = ["//:__subpackages__"],
12+
)
13+
14+
py_test(
15+
name = "test_util",
16+
srcs = ["test_util.py"],
17+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Sibling imports disabled
2+
3+
This test case asserts that imports from sibling modules are NOT resolved as
4+
absolute imports when the `python_resolve_sibling_imports` directive is
5+
disabled. It covers 3 different types of imports in `pkg/unit_test.py`:
6+
7+
- `import a` - resolves to the root-level `a.py` instead of the sibling
8+
`pkg/a.py`
9+
- `import test_util` - resolves to the root-level `test_util.py` instead of
10+
the sibling `pkg/test_util.py`
11+
- `from b import run` - resolves to the root-level `b.py` instead of the
12+
sibling `pkg/b.py`
13+
14+
When sibling imports are disabled with
15+
`# gazelle:python_resolve_sibling_imports false`, the imports remain as-is
16+
and follow standard Python resolution rules where absolute imports can't refer
17+
to sibling modules.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This is a Bazel workspace for the Gazelle test data.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Root level a.py file for testing disabled sibling imports
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Root level b.py file for testing disabled sibling imports
2+
def run():
3+
pass

0 commit comments

Comments
 (0)