diff --git a/CHANGELOG.md b/CHANGELOG.md index 415b936e8..449dae0cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,8 @@ A brief description of the categories of changes: the whl and sdist files will be written to the lock file. Controlling whether the downloading of metadata is done in parallel can be done using `parallel_download` attribute. +* (gazelle) Add a new annotation `include_deps`. Also add documentation for + annotations to `gazelle/README.md`. * (deps): `rules_python` depends now on `rules_cc` 0.0.9 * (pip_parse): A new flag `use_hub_alias_dependencies` has been added that is going to become default in the next release. This makes use of `dep_template` flag diff --git a/gazelle/README.md b/gazelle/README.md index 4c1cb2799..e7b17669a 100644 --- a/gazelle/README.md +++ b/gazelle/README.md @@ -425,6 +425,108 @@ py_library( [issue-1826]: https://github.com/bazelbuild/rules_python/issues/1826 +### Annotations + +*Annotations* refer to comments found _within Python files_ that configure how +Gazelle acts for that particular file. + +Annotations have the form: + +```python +# gazelle:annotation_name value +``` + +and can reside anywhere within a Python file where comments are valid. For example: + +```python +import foo +# gazelle:annotation_name value + +def bar(): # gazelle:annotation_name value + pass +``` + +The annotations are: + +| **Annotation** | **Default value** | +|---------------------------------------------------------------|-------------------| +| [`# gazelle:ignore imports`](#annotation-ignore) | N/A | +| Tells Gazelle to ignore import statements. `imports` is a comma-separated list of imports to ignore. | | +| [`# gazelle:include_dep targets`](#annotation-include_dep) | N/A | +| Tells Gazelle to include a set of dependencies, even if they are not imported in a Python module. `targets` is a comma-separated list of target names to include as dependencies. | | + + +#### Annotation: `ignore` + +This annotation accepts a comma-separated string of values. Values are names of Python +imports that Gazelle should _not_ include in target dependencies. + +The annotation can be added multiple times, and all values are combined and +de-duplicated. + +For `python_generation_mode = "package"`, the `ignore` annotations +found across all files included in the generated target are removed from `deps`. + +Example: + +```python +import numpy # a pypi package + +# gazelle:ignore bar.baz.hello,foo +import bar.baz.hello +import foo + +# Ignore this import because _reasons_ +import baz # gazelle:ignore baz +``` + +will cause Gazelle to generate: + +```starlark +deps = ["@pypi//numpy"], +``` + + +#### Annotation: `include_dep` + +This annotation accepts a comma-separated string of values. Values _must_ +be Python targets, but _no validation is done_. If a value is not a Python +target, building will result in an error saying: + +``` + does not have mandatory providers: 'PyInfo' or 'CcInfo' or 'PyInfo'. +``` + +Adding non-Python targets to the generated target is a feature request being +tracked in [Issue #1865](https://github.com/bazelbuild/rules_python/issues/1865). + +The annotation can be added multiple times, and all values are combined +and de-duplicated. + +For `python_generation_mode = "package"`, the `include_dep` annotations +found across all files included in the generated target are included in `deps`. + +Example: + +```python +# gazelle:include_dep //foo:bar,:hello_world,//:abc +# gazelle:include_dep //:def,//foo:bar +import numpy # a pypi package +``` + +will cause Gazelle to generate: + +```starlark +deps = [ + ":hello_world", + "//:abc", + "//:def", + "//foo:bar", + "@pypi//numpy", +] +``` + + ### Libraries Python source files are those ending in `.py` but not ending in `_test.py`. diff --git a/gazelle/python/generate.go b/gazelle/python/generate.go index 1937831c4..8889438c0 100644 --- a/gazelle/python/generate.go +++ b/gazelle/python/generate.go @@ -233,7 +233,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes collisionErrors := singlylinkedlist.New() appendPyLibrary := func(srcs *treeset.Set, pyLibraryTargetName string) { - allDeps, mainModules, err := parser.parse(srcs) + allDeps, mainModules, annotations, err := parser.parse(srcs) if err != nil { log.Fatalf("ERROR: %v\n", err) } @@ -263,6 +263,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes addVisibility(visibility). addSrc(filename). addModuleDependencies(mainModules[filename]). + addResolvedDependencies(annotations.includeDeps). generateImportsAttribute().build() result.Gen = append(result.Gen, pyBinary) result.Imports = append(result.Imports, pyBinary.PrivateAttr(config.GazelleImportsKey)) @@ -290,6 +291,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes addVisibility(visibility). addSrcs(srcs). addModuleDependencies(allDeps). + addResolvedDependencies(annotations.includeDeps). generateImportsAttribute(). build() @@ -314,7 +316,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes } if hasPyBinaryEntryPointFile { - deps, _, err := parser.parseSingle(pyBinaryEntrypointFilename) + deps, _, annotations, err := parser.parseSingle(pyBinaryEntrypointFilename) if err != nil { log.Fatalf("ERROR: %v\n", err) } @@ -338,6 +340,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes addVisibility(visibility). addSrc(pyBinaryEntrypointFilename). addModuleDependencies(deps). + addResolvedDependencies(annotations.includeDeps). generateImportsAttribute() pyBinary := pyBinaryTarget.build() @@ -348,7 +351,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes var conftest *rule.Rule if hasConftestFile { - deps, _, err := parser.parseSingle(conftestFilename) + deps, _, annotations, err := parser.parseSingle(conftestFilename) if err != nil { log.Fatalf("ERROR: %v\n", err) } @@ -367,6 +370,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes conftestTarget := newTargetBuilder(pyLibraryKind, conftestTargetname, pythonProjectRoot, args.Rel, pyFileNames). addSrc(conftestFilename). addModuleDependencies(deps). + addResolvedDependencies(annotations.includeDeps). addVisibility(visibility). setTestonly(). generateImportsAttribute() @@ -379,7 +383,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes var pyTestTargets []*targetBuilder newPyTestTargetBuilder := func(srcs *treeset.Set, pyTestTargetName string) *targetBuilder { - deps, _, err := parser.parse(srcs) + deps, _, annotations, err := parser.parse(srcs) if err != nil { log.Fatalf("ERROR: %v\n", err) } @@ -397,6 +401,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes return newTargetBuilder(pyTestKind, pyTestTargetName, pythonProjectRoot, args.Rel, pyFileNames). addSrcs(srcs). addModuleDependencies(deps). + addResolvedDependencies(annotations.includeDeps). generateImportsAttribute() } if (hasPyTestEntryPointFile || hasPyTestEntryPointTarget || cfg.CoarseGrainedGeneration()) && !cfg.PerFileGeneration() { diff --git a/gazelle/python/parser.go b/gazelle/python/parser.go index 9b00b831e..184fad7c1 100644 --- a/gazelle/python/parser.go +++ b/gazelle/python/parser.go @@ -101,7 +101,7 @@ func newPython3Parser( // parseSingle parses a single Python file and returns the extracted modules // from the import statements as well as the parsed comments. -func (p *python3Parser) parseSingle(pyFilename string) (*treeset.Set, map[string]*treeset.Set, error) { +func (p *python3Parser) parseSingle(pyFilename string) (*treeset.Set, map[string]*treeset.Set, *annotations, error) { pyFilenames := treeset.NewWith(godsutils.StringComparator) pyFilenames.Add(pyFilename) return p.parse(pyFilenames) @@ -109,7 +109,7 @@ func (p *python3Parser) parseSingle(pyFilename string) (*treeset.Set, map[string // parse parses multiple Python files and returns the extracted modules from // the import statements as well as the parsed comments. -func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, map[string]*treeset.Set, error) { +func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, map[string]*treeset.Set, *annotations, error) { parserMutex.Lock() defer parserMutex.Unlock() @@ -122,28 +122,30 @@ func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, map[strin } encoder := json.NewEncoder(parserStdin) if err := encoder.Encode(&req); err != nil { - return nil, nil, fmt.Errorf("failed to parse: %w", err) + return nil, nil, nil, fmt.Errorf("failed to parse: %w", err) } reader := bufio.NewReader(parserStdout) data, err := reader.ReadBytes(0) if err != nil { - return nil, nil, fmt.Errorf("failed to parse: %w", err) + return nil, nil, nil, fmt.Errorf("failed to parse: %w", err) } data = data[:len(data)-1] var allRes []parserResponse if err := json.Unmarshal(data, &allRes); err != nil { - return nil, nil, fmt.Errorf("failed to parse: %w", err) + return nil, nil, nil, fmt.Errorf("failed to parse: %w", err) } mainModules := make(map[string]*treeset.Set, len(allRes)) + allAnnotations := new(annotations) + allAnnotations.ignore = make(map[string]struct{}) for _, res := range allRes { if res.HasMain { mainModules[res.FileName] = treeset.NewWith(moduleComparator) } annotations, err := annotationsFromComments(res.Comments) if err != nil { - return nil, nil, fmt.Errorf("failed to parse annotations: %w", err) + return nil, nil, nil, fmt.Errorf("failed to parse annotations: %w", err) } for _, m := range res.Modules { @@ -164,9 +166,32 @@ func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, map[strin mainModules[res.FileName].Add(m) } } + + // Collect all annotations from each file into a single annotations struct. + for k, v := range annotations.ignore { + allAnnotations.ignore[k] = v + } + allAnnotations.includeDeps = append(allAnnotations.includeDeps, annotations.includeDeps...) } - return modules, mainModules, nil + allAnnotations.includeDeps = removeDupesFromStringTreeSetSlice(allAnnotations.includeDeps) + + return modules, mainModules, allAnnotations, nil +} + +// removeDupesFromStringTreeSetSlice takes a []string, makes a set out of the +// elements, and then returns a new []string with all duplicates removed. Order +// is preserved. +func removeDupesFromStringTreeSetSlice(array []string) []string { + s := treeset.NewWith(godsutils.StringComparator) + for _, v := range array { + s.Add(v) + } + dedupe := make([]string, s.Size()) + for i, v := range s.Values() { + dedupe[i] = fmt.Sprint(v) + } + return dedupe } // parserResponse represents a response returned by the parser.py for a given @@ -211,7 +236,8 @@ const ( // The Gazelle annotation prefix. annotationPrefix string = "gazelle:" // The ignore annotation kind. E.g. '# gazelle:ignore '. - annotationKindIgnore annotationKind = "ignore" + annotationKindIgnore annotationKind = "ignore" + annotationKindIncludeDep annotationKind = "include_dep" ) // comment represents a Python comment. @@ -247,12 +273,15 @@ type annotation struct { type annotations struct { // The parsed modules to be ignored by Gazelle. ignore map[string]struct{} + // Labels that Gazelle should include as deps of the generated target. + includeDeps []string } // annotationsFromComments returns all the annotations parsed out of the // comments of a Python module. func annotationsFromComments(comments []comment) (*annotations, error) { ignore := make(map[string]struct{}) + includeDeps := []string{} for _, comment := range comments { annotation, err := comment.asAnnotation() if err != nil { @@ -269,10 +298,21 @@ func annotationsFromComments(comments []comment) (*annotations, error) { ignore[m] = struct{}{} } } + if annotation.kind == annotationKindIncludeDep { + targets := strings.Split(annotation.value, ",") + for _, t := range targets { + if t == "" { + continue + } + t = strings.TrimSpace(t) + includeDeps = append(includeDeps, t) + } + } } } return &annotations{ - ignore: ignore, + ignore: ignore, + includeDeps: includeDeps, }, nil } diff --git a/gazelle/python/target.go b/gazelle/python/target.go index a941a7cc7..c40d6fb3b 100644 --- a/gazelle/python/target.go +++ b/gazelle/python/target.go @@ -99,6 +99,15 @@ func (t *targetBuilder) addResolvedDependency(dep string) *targetBuilder { return t } +// addResolvedDependencies adds multiple dependencies, that have already been +// resolved or generated, to the target. +func (t *targetBuilder) addResolvedDependencies(deps []string) *targetBuilder { + for _, dep := range deps { + t.addResolvedDependency(dep) + } + return t +} + // addVisibility adds visibility labels to the target. func (t *targetBuilder) addVisibility(visibility []string) *targetBuilder { for _, item := range visibility { diff --git a/gazelle/python/testdata/annotation_include_dep/BUILD.in b/gazelle/python/testdata/annotation_include_dep/BUILD.in new file mode 100644 index 000000000..af2c2cea4 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/BUILD.in @@ -0,0 +1 @@ +# gazelle:python_generation_mode file diff --git a/gazelle/python/testdata/annotation_include_dep/BUILD.out b/gazelle/python/testdata/annotation_include_dep/BUILD.out new file mode 100644 index 000000000..1cff8f467 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/BUILD.out @@ -0,0 +1,53 @@ +load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test") + +# gazelle:python_generation_mode file + +py_library( + name = "__init__", + srcs = ["__init__.py"], + visibility = ["//:__subpackages__"], + deps = [ + ":module1", + ":module2", + "//foo/bar:baz", + "//hello:world", + "@gazelle_python_test//foo", + "@star_wars//rebel_alliance/luke:skywalker", + ], +) + +py_library( + name = "module1", + srcs = ["module1.py"], + visibility = ["//:__subpackages__"], +) + +py_library( + name = "module2", + srcs = ["module2.py"], + visibility = ["//:__subpackages__"], + deps = [ + "//checking/py_binary/from/if:works", + "//foo:bar", + ], +) + +py_binary( + name = "annotation_include_dep_bin", + srcs = ["__main__.py"], + main = "__main__.py", + visibility = ["//:__subpackages__"], + deps = [ + ":module2", + "//checking/py_binary/from/__main__:works", + ], +) + +py_test( + name = "module2_test", + srcs = ["module2_test.py"], + deps = [ + ":module2", + "//checking/py_test/works:too", + ], +) diff --git a/gazelle/python/testdata/annotation_include_dep/README.md b/gazelle/python/testdata/annotation_include_dep/README.md new file mode 100644 index 000000000..4c8afbe5e --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/README.md @@ -0,0 +1,10 @@ +# Annotation: Include Dep + +Test that the Python gazelle annotation `# gazelle:include_dep` correctly adds dependences +to the generated target even if those dependencies are not imported by the Python module. + +The root directory tests that all `py_*` targets will correctly include the additional +dependencies. + +The `subpkg` directory tests that all `# gazlle:include_dep` annotations found in all source +files are included in the generated target (such as during `generation_mode package`). diff --git a/gazelle/python/testdata/invalid_annotation/BUILD.in b/gazelle/python/testdata/annotation_include_dep/WORKSPACE similarity index 100% rename from gazelle/python/testdata/invalid_annotation/BUILD.in rename to gazelle/python/testdata/annotation_include_dep/WORKSPACE diff --git a/gazelle/python/testdata/annotation_include_dep/__init__.py b/gazelle/python/testdata/annotation_include_dep/__init__.py new file mode 100644 index 000000000..61015346d --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/__init__.py @@ -0,0 +1,9 @@ +import module1 +import foo # third party package + +# gazelle:include_dep //foo/bar:baz +# gazelle:include_dep //hello:world,@star_wars//rebel_alliance/luke:skywalker +# gazelle:include_dep :module2 + +del module1 +del foo diff --git a/gazelle/python/testdata/annotation_include_dep/__main__.py b/gazelle/python/testdata/annotation_include_dep/__main__.py new file mode 100644 index 000000000..6d9d8aa24 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/__main__.py @@ -0,0 +1,7 @@ +# gazelle:include_dep //checking/py_binary/from/__main__:works +# Check deduping +# gazelle:include_dep //checking/py_binary/from/__main__:works + +import module2 + +del module2 diff --git a/gazelle/python/testdata/annotation_include_dep/gazelle_python.yaml b/gazelle/python/testdata/annotation_include_dep/gazelle_python.yaml new file mode 100644 index 000000000..7afe81f81 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/gazelle_python.yaml @@ -0,0 +1,18 @@ +# Copyright 2024 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. + +manifest: + modules_mapping: + foo: foo + pip_deps_repository_name: gazelle_python_test diff --git a/gazelle/python/testdata/invalid_annotation/BUILD.out b/gazelle/python/testdata/annotation_include_dep/module1.py similarity index 100% rename from gazelle/python/testdata/invalid_annotation/BUILD.out rename to gazelle/python/testdata/annotation_include_dep/module1.py diff --git a/gazelle/python/testdata/annotation_include_dep/module2.py b/gazelle/python/testdata/annotation_include_dep/module2.py new file mode 100644 index 000000000..23a75afee --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/module2.py @@ -0,0 +1,5 @@ +# gazelle:include_dep //foo:bar + +if __name__ == "__main__": + # gazelle:include_dep //checking/py_binary/from/if:works + print("hello") diff --git a/gazelle/python/testdata/annotation_include_dep/module2_test.py b/gazelle/python/testdata/annotation_include_dep/module2_test.py new file mode 100644 index 000000000..6fa18c6f5 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/module2_test.py @@ -0,0 +1,5 @@ +# gazelle:include_dep //checking/py_test/works:too + +import module2 + +del module2 diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/BUILD.in b/gazelle/python/testdata/annotation_include_dep/subpkg/BUILD.in new file mode 100644 index 000000000..421b48688 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/subpkg/BUILD.in @@ -0,0 +1 @@ +# gazelle:python_generation_mode package diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/BUILD.out b/gazelle/python/testdata/annotation_include_dep/subpkg/BUILD.out new file mode 100644 index 000000000..921c89288 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/subpkg/BUILD.out @@ -0,0 +1,29 @@ +load("@rules_python//python:defs.bzl", "py_library", "py_test") + +# gazelle:python_generation_mode package + +py_library( + name = "subpkg", + srcs = [ + "__init__.py", + "module1.py", + "module2.py", + "module3.py", + ], + visibility = ["//:__subpackages__"], + deps = [ + ":nonexistant_target_from_include_dep_in_module3", + "//me_from_module1", + "//other/thing:from_include_dep_in_module2", + "//you_from_module1", + ], +) + +py_test( + name = "module1_test", + srcs = ["module1_test.py"], + deps = [ + ":subpkg", + "//:bagel_from_include_dep_in_module1_test", + ], +) diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/__init__.py b/gazelle/python/testdata/annotation_include_dep/subpkg/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/module1.py b/gazelle/python/testdata/annotation_include_dep/subpkg/module1.py new file mode 100644 index 000000000..01566a07e --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/subpkg/module1.py @@ -0,0 +1,3 @@ +def hello(): + # gazelle:include_dep //you_from_module1,//me_from_module1 + pass diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/module1_test.py b/gazelle/python/testdata/annotation_include_dep/subpkg/module1_test.py new file mode 100644 index 000000000..087763a69 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/subpkg/module1_test.py @@ -0,0 +1,5 @@ +# gazelle:include_dep //:bagel_from_include_dep_in_module1_test + +import module1 + +del module1 diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/module2.py b/gazelle/python/testdata/annotation_include_dep/subpkg/module2.py new file mode 100644 index 000000000..dabeb6794 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/subpkg/module2.py @@ -0,0 +1,4 @@ +# gazelle:include_dep //other/thing:from_include_dep_in_module2 +import module1 + +del module1 diff --git a/gazelle/python/testdata/annotation_include_dep/subpkg/module3.py b/gazelle/python/testdata/annotation_include_dep/subpkg/module3.py new file mode 100644 index 000000000..899a7c4f5 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/subpkg/module3.py @@ -0,0 +1,3 @@ +def goodbye(): + # gazelle:include_dep :nonexistant_target_from_include_dep_in_module3 + pass diff --git a/gazelle/python/testdata/annotation_include_dep/test.yaml b/gazelle/python/testdata/annotation_include_dep/test.yaml new file mode 100644 index 000000000..2410223e5 --- /dev/null +++ b/gazelle/python/testdata/annotation_include_dep/test.yaml @@ -0,0 +1,17 @@ +# 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. + +--- +expect: + exit_code: 0 diff --git a/gazelle/python/testdata/invalid_annotation_exclude/BUILD.in b/gazelle/python/testdata/invalid_annotation_exclude/BUILD.in new file mode 100644 index 000000000..e69de29bb diff --git a/gazelle/python/testdata/invalid_annotation_exclude/BUILD.out b/gazelle/python/testdata/invalid_annotation_exclude/BUILD.out new file mode 100644 index 000000000..e69de29bb diff --git a/gazelle/python/testdata/invalid_annotation/README.md b/gazelle/python/testdata/invalid_annotation_exclude/README.md similarity index 100% rename from gazelle/python/testdata/invalid_annotation/README.md rename to gazelle/python/testdata/invalid_annotation_exclude/README.md diff --git a/gazelle/python/testdata/invalid_annotation/WORKSPACE b/gazelle/python/testdata/invalid_annotation_exclude/WORKSPACE similarity index 100% rename from gazelle/python/testdata/invalid_annotation/WORKSPACE rename to gazelle/python/testdata/invalid_annotation_exclude/WORKSPACE diff --git a/gazelle/python/testdata/invalid_annotation/__init__.py b/gazelle/python/testdata/invalid_annotation_exclude/__init__.py similarity index 100% rename from gazelle/python/testdata/invalid_annotation/__init__.py rename to gazelle/python/testdata/invalid_annotation_exclude/__init__.py diff --git a/gazelle/python/testdata/invalid_annotation/test.yaml b/gazelle/python/testdata/invalid_annotation_exclude/test.yaml similarity index 100% rename from gazelle/python/testdata/invalid_annotation/test.yaml rename to gazelle/python/testdata/invalid_annotation_exclude/test.yaml diff --git a/gazelle/python/testdata/invalid_annotation_include_dep/BUILD.in b/gazelle/python/testdata/invalid_annotation_include_dep/BUILD.in new file mode 100644 index 000000000..e69de29bb diff --git a/gazelle/python/testdata/invalid_annotation_include_dep/BUILD.out b/gazelle/python/testdata/invalid_annotation_include_dep/BUILD.out new file mode 100644 index 000000000..e69de29bb diff --git a/gazelle/python/testdata/invalid_annotation_include_dep/README.md b/gazelle/python/testdata/invalid_annotation_include_dep/README.md new file mode 100644 index 000000000..2f8e02405 --- /dev/null +++ b/gazelle/python/testdata/invalid_annotation_include_dep/README.md @@ -0,0 +1,3 @@ +# Invalid annotation +This test case asserts that the parse step fails as expected due to invalid annotation format of +the `include_dep` annotation. diff --git a/gazelle/python/testdata/invalid_annotation_include_dep/WORKSPACE b/gazelle/python/testdata/invalid_annotation_include_dep/WORKSPACE new file mode 100644 index 000000000..faff6af87 --- /dev/null +++ b/gazelle/python/testdata/invalid_annotation_include_dep/WORKSPACE @@ -0,0 +1 @@ +# This is a Bazel workspace for the Gazelle test data. diff --git a/gazelle/python/testdata/invalid_annotation_include_dep/__init__.py b/gazelle/python/testdata/invalid_annotation_include_dep/__init__.py new file mode 100644 index 000000000..61f4c76c3 --- /dev/null +++ b/gazelle/python/testdata/invalid_annotation_include_dep/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 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. + +# gazelle:include_dep diff --git a/gazelle/python/testdata/invalid_annotation_include_dep/test.yaml b/gazelle/python/testdata/invalid_annotation_include_dep/test.yaml new file mode 100644 index 000000000..f2159a6cd --- /dev/null +++ b/gazelle/python/testdata/invalid_annotation_include_dep/test.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 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. + +--- +expect: + exit_code: 1 + stderr: | + gazelle: ERROR: failed to parse annotations: `# gazelle:include_dep` requires a value