blob: a553226a5996d0acf1fa35e6548df7cf418be2b5 [file] [log] [blame] [view]
# Directives
You can configure the extension using directives, just like for other
languages. These are just comments in the `BUILD.bazel` file which
govern behavior of the extension when processing files under that
folder.
See the [Gazelle docs on directives][gazelle-directives] for some general
directives that may be useful. In particular, the `resolve` directive
is language-specific and can be used with Python. Examples of these and
the Python-specific directives in use can be found in the
{gh-path}`gazelle/testdata` folder in the `rules_python` repo.
[gazelle-directives]: https://github.com/bazelbuild/bazel-gazelle#directives
The Python-specific directives are:
{.glossary}
[`# gazelle:python_extension value`](#python-extension)
: Controls whether the Python extension is enabled or not. Sub-packages
inherit this value.
* Default: `enabled`
* Allowed Values: `enabled`, `disabled`
[`# gazelle:python_root`](#python-root)
: Sets a Bazel package as a Python root. This is used on monorepos with
multiple Python projects that don't share the top-level of the workspace
as the root.
* Default: n/a
* Allowed Values: None. This direcive does not consume values.
[`# gazelle:python_manifest_file_name value`](#python-manifest-file-name)
: Overrides the default manifest file name.
* Default: `gazelle_python.yaml`
* Allowed Values: A string
[`# gazelle:python_ignore_files value`](#python-ignore-files)
: Controls the files which are ignored from the generated targets.
* Default: n/a
* Allowed Values: A comma-separated list of strings.
[`# gazelle:python_ignore_dependencies value`](#python-ignore-dependencies)
: Controls the ignored dependencies from the generated targets.
* Default: n/a
* Allowed Values: A comma-separated list of strings.
[`# gazelle:python_validate_import_statements bool`](#python-validate-import-statements)
: Controls whether the Python import statements should be validated.
* Default: `true`
* Allowed Values: `true`, `false`
[`# gazelle:python_generation_mode value`](#python-generation-mode)
: Controls the target generation mode.
* Default: `package`
* Allowed Values: `file`, `package`, `project`
[`# gazelle:python_generation_mode_per_file_include_init bool`](#python-generation-mode-per-file-include-init)
: Controls whether `__init__.py` files are included as srcs in each
generated target when target generation mode is "file".
* Default: `false`
* Allowed Values: `true`, `false`
[`# gazelle:python_generation_mode_per_package_require_test_entry_point bool`](python-generation-mode-per-package-require-test-entry-point)
: Controls whether a file called `__test__.py` or a target called
`__test__` is required to generate one test target per package in
package mode.
* Default: `true`
* Allowed Values: `true`, `false`
[`# gazelle:python_library_naming_convention value`](#python-library-naming-convention)
: Controls the {bzl:obj}`py_library` naming convention. It interpolates
`$package_name$` with the Bazel package name. E.g. if the Bazel package
name is `foo`, setting this to `$package_name$_my_lib` would result in a
generated target named `foo_my_lib`.
* Default: `$package_name$`
* Allowed Values: A string containing `"$package_name$"`
[`# gazelle:python_binary_naming_convention value`](#python-binary-naming-convention)
: Controls the {bzl:obj}`py_binary` naming convention. Follows the same interpolation
rules as `python_library_naming_convention`.
* Default: `$package_name$_bin`
* Allowed Values: A string containing `"$package_name$"`
[`# gazelle:python_test_naming_convention value`](#python-test-naming-convention)
: Controls the {bzl:obj}`py_test` naming convention. Follows the same interpolation
rules as `python_library_naming_convention`.
* Default: `$package_name$_test`
* Allowed Values: A string containing `"$package_name$"`
[`# gazelle:python_proto_naming_convention value`](#python-proto-naming-convention)
: Controls the {bzl:obj}`py_proto_library` naming convention. It interpolates
`$proto_name$` with the {bzl:obj}`proto_library` rule name, minus any trailing
`_proto`. E.g. if the {bzl:obj}`proto_library` name is `foo_proto`, setting this
to `$proto_name$_my_lib` would render to `foo_my_lib`.
* Default: `$proto_name$_py_pb2`
* Allowed Values: A string containing `"$proto_name$"`
[`# gazelle:resolve py import-lang import-string label`](#resolve-py)
: Instructs the plugin what target to add as a dependency to satisfy a given
import statement. The syntax is `# gazelle:resolve py import-string label`
where `import-string` is the symbol in the python `import` statement,
and `label` is the Bazel label that Gazelle should write in `deps`.
* Default: n/a
* Allowed Values: See the [bazel-gazelle docs][gazelle-directives]
[`# gazelle:python_default_visibility labels`](python-default-visibility)
: Instructs gazelle to use these visibility labels on all python targets.
`labels` is a comma-separated list of labels (without spaces).
* Default: `//$python_root$:__subpackages__`
* Allowed Values: A string
[`# gazelle:python_visibility label`](python-visibility)
: Appends additional visibility labels to each generated target. This r
directive can be set multiple times.
* Default: n/a
* Allowed Values: A string
[`# gazelle:python_test_file_pattern value`](python-test-file-pattern)
: Filenames matching these comma-separated {command}`glob`s will be mapped to
{bzl:obj}`py_test` targets.
* Default: `*_test.py,test_*.py`
* Allowed Values: A glob string
[`# gazelle:python_label_convention value`](#python-label-convention)
: Defines the format of the distribution name in labels to third-party deps.
Useful for using Gazelle plugin with other rules with different repository
conventions (e.g. `rules_pycross`). Full label is always prepended with
the `pip` repository name, e.g. `@pip//numpy` if your
`MODULE.bazel` has `use_repo(pip, "pip")` or `@pypi//numpy`
if your `MODULE.bazel` has `use_repo(pip, "pypi")`.
* Default: `$distribution_name$`
* Allowed Values: A string
[`# gazelle:python_label_normalization value`](#python-label-normalization)
: Controls how distribution names in labels to third-party deps are
normalized. Useful for using Gazelle plugin with other rules with different
label conventions (e.g. `rules_pycross` uses PEP-503).
* Default: `snake_case`
* Allowed Values: `snake_case`, `none`, `pep503`
[`# gazelle:python_experimental_allow_relative_imports bool`](#python-experimental-allow-relative-imports)
: Controls whether Gazelle resolves dependencies for import statements that
use paths relative to the current package.
* Default: `false`
* Allowed Values: `true`, `false`
[`# gazelle:python_generate_pyi_deps bool`](#python-generate-pyi-deps)
: Controls whether to generate a separate `pyi_deps` attribute for
type-checking dependencies or merge them into the regular `deps`
attribute. When `false` (default), type-checking dependencies are
merged into `deps` for backward compatibility. When `true`, generates
separate `pyi_deps`. Imports in blocks with the format
`if typing.TYPE_CHECKING:` or `if TYPE_CHECKING:` and type-only stub
packages (eg. boto3-stubs) are recognized as type-checking dependencies.
* Default: `false`
* Allowed Values: `true`, `false`
[`# gazelle:python_generate_proto bool`](#python-generate-proto)
: Controls whether to generate a {bzl:obj}`py_proto_library` for each
{bzl:obj}`proto_library` in the package. By default we load this rule from the
`@protobuf` repository; use `gazelle:map_kind` if you need to load this
from somewhere else.
* Default: `false`
* Allowed Values: `true`, `false`
[`# gazelle:python_resolve_sibling_imports bool`](#python-resolve-sibling-imports)
: Allows absolute imports to be resolved to sibling modules (Python 2's
behavior without `absolute_import`).
* Default: `false`
* Allowed Values: `true`, `false`
## `python_extension`
:::{error}
Detailed docs are not yet written.
:::
## `python_root`
Set this directive within the Bazel package that you want to use as the Python root.
For example, if using a `src` dir (as recommended by the [Python Packaging User
Guide][python-packaging-user-guide]), then set this directive in `src/BUILD.bazel`:
```starlark
# ./src/BUILD.bazel
# Tell gazelle that are python root is the same dir as this Bazel package.
# gazelle:python_root
```
Note that the directive does not have any arguments.
Gazelle will then add the necessary `imports` attribute to all targets that it
generates:
```starlark
# in ./src/foo/BUILD.bazel
py_libary(
...
imports = [".."], # Gazelle adds this
...
)
# in ./src/foo/bar/BUILD.bazel
py_libary(
...
imports = ["../.."], # Gazelle adds this
...
)
```
[python-packaging-user-guide]: https://github.com/pypa/packaging.python.org/blob/4c86169a/source/tutorials/packaging-projects.rst
## `python_manifest_file_name`
:::{error}
Detailed docs are not yet written.
:::
## `python_ignore_files`
:::{error}
Detailed docs are not yet written.
:::
## `python_ignore_dependencies`
:::{error}
Detailed docs are not yet written.
:::
## `python_validate_import_statements`
:::{error}
Detailed docs are not yet written.
:::
## `python_generation_mode`
:::{error}
Detailed docs are not yet written.
:::
## `python_generation_mode_per_file_include_init`
:::{error}
Detailed docs are not yet written.
:::
## `python_generation_mode_per_package_require_test_entry_point`
When `# gazelle:python_generation_mode package`, whether a file called
`__test__.py` or a target called `__test__`, a.k.a., entry point, is required
to generate one test target per package. If this is set to true but no entry
point is found, Gazelle will fall back to file mode and generate one test target
per file. Setting this directive to false forces Gazelle to generate one test
target per package even without entry point. However, this means the `main`
attribute of the {bzl:obj}`py_test` will not be set and the target will not be runnable
unless either:
1. there happen to be a file in the `srcs` with the same name as the {bzl:obj}`py_test`
target, or
2. a macro populating the `main` attribute of {bzl:obj}`py_test` is configured with
`gazelle:map_kind` to replace {bzl:obj}`py_test` when Gazelle is generating Python
test targets. For example, user can provide such a macro to Gazelle:
```starlark
load("@rules_python//python:defs.bzl", _py_test="py_test")
load("@aspect_rules_py//py:defs.bzl", "py_pytest_main")
def py_test(name, main=None, **kwargs):
deps = kwargs.pop("deps", [])
if not main:
py_pytest_main(
name = "__test__",
deps = ["@pip_pytest//:pkg"], # change this to the pytest target in your repo.
)
deps.append(":__test__")
main = ":__test__.py"
_py_test(
name = name,
main = main,
deps = deps,
**kwargs,
)
```
## `python_library_naming_convention`
:::{error}
Detailed docs are not yet written.
:::
## `python_binary_naming_convention`
:::{error}
Detailed docs are not yet written.
:::
## `python_test_naming_convention`
:::{error}
Detailed docs are not yet written.
:::
## `python_proto_naming_convention`
Set this directive to a string pattern to control how the generated
{bzl:obj}`py_proto_library` targets are named. When generating new
{bzl:obj}`py_proto_library` rules, Gazelle will replace `$proto_name$` in the
pattern with the name of the {bzl:obj}`proto_library` rule, stripping out a
trailing `_proto`. For example:
```starlark
# gazelle:python_generate_proto true
# gazelle:python_proto_naming_convention my_custom_$proto_name$_pattern
proto_library(
name = "foo_proto",
srcs = ["foo.proto"],
)
```
produces the following {bzl:obj}`py_proto_library` rule:
```starlark
py_proto_library(
name = "my_custom_foo_pattern",
deps = [":foo_proto"],
)
```
The default naming convention is `$proto_name$_pb2_py` in accordance with
the [Bazel `py_proto_library` convention][bazel-py-proto-library], so by default
in the above example Gazelle would generate `foo_pb2_py`. Any pre-existing
rules are left in place and not renamed.
[bazel-py-proto-library]: https://bazel.build/reference/be/protocol-buffer#py_proto_library
Note that the Python library will always be imported as `foo_pb2` in Python
code, regardless of the naming convention. Also note that Gazelle is currently
not able to map said imports, e.g. `import foo_pb2`, to fill in
{bzl:obj}`py_proto_library` targets as dependencies of other rules. See
{gh-issue}`1703`.
## `resolve py`
:::{error}
Detailed docs are not yet written.
:::
## `python_default_visibility`
Instructs gazelle to use these visibility labels on all _python_ targets
(typically `py_*`, but can be modified via the `map_kind` directive). The arg
to this directive is a comma-separated list (without spaces) of labels.
For example:
```starlark
# gazelle:python_default_visibility //:__subpackages__,//tests:__subpackages__
```
produces the following visibility attribute:
```starlark
py_library(
...,
visibility = [
"//:__subpackages__",
"//tests:__subpackages__",
],
...,
)
```
You can also inject the `python_root` value by using the exact string
`$python_root$`. All instances of this string will be replaced by the `python_root`
value.
```starlark
# gazelle:python_default_visibility //$python_root$:__pkg__,//foo/$python_root$/tests:__subpackages__
# Assuming the "# gazelle:python_root" directive is set in ./py/src/BUILD.bazel,
# the results will be:
py_library(
...,
visibility = [
"//foo/py/src/tests:__subpackages__", # sorted alphabetically
"//py/src:__pkg__",
],
...,
)
```
Two special values are also accepted as an argument to the directive:
* `NONE`: This removes all default visibility. Labels added by the
`python_visibility` directive are still included.
* `DEFAULT`: This resets the default visibility.
For example:
```starlark
# gazelle:python_default_visibility NONE
py_library(
name = "...",
srcs = [...],
)
```
```starlark
# gazelle:python_default_visibility //foo:bar
# gazelle:python_default_visibility DEFAULT
py_library(
...,
visibility = ["//:__subpackages__"],
...,
)
```
These special values can be useful for sub-packages.
## `python_visibility`
Appends additional `visibility` labels to each generated target.
This directive can be set multiple times. The generated `visibility` attribute
will include the default visibility and all labels defined by this directive.
All labels will be ordered alphabetically.
```starlark
# ./BUILD.bazel
# gazelle:python_visibility //tests:__pkg__
# gazelle:python_visibility //bar:baz
py_library(
...
visibility = [
"//:__subpackages__", # default visibility
"//bar:baz",
"//tests:__pkg__",
],
...
)
```
Child Bazel packages inherit values from parents:
```starlark
# ./bar/BUILD.bazel
# gazelle:python_visibility //tests:__subpackages__
py_library(
...
visibility = [
"//:__subpackages__", # default visibility
"//bar:baz", # defined in ../BUILD.bazel
"//tests:__pkg__", # defined in ../BUILD.bazel
"//tests:__subpackages__", # defined in this ./BUILD.bazel
],
...
)
```
This directive also supports the `$python_root$` placeholder that
`# gazelle:python_default_visibility` supports.
```starlark
# gazlle:python_visibility //$python_root$/foo:bar
py_library(
...
visibility = ["//this_is_my_python_root/foo:bar"],
...
)
```
## `python_test_file_pattern`
This directive adjusts which python files will be mapped to the {bzl:obj}`py_test` rule.
+ The default is `*_test.py,test_*.py`: both `test_*.py` and `*_test.py` files
will generate {bzl:obj}`py_test` targets.
+ This directive must have a value. If no value is given, an error will be raised.
+ It is recommended, though not necessary, to include the `.py` extension in
the {command}`glob`: `foo*.py,?at.py`.
+ Like most directives, it applies to the current Bazel package and all subpackages
until the directive is set again.
+ This directive accepts multiple {command}`glob` patterns, separated by commas without spaces:
```starlark
# gazelle:python_test_file_pattern foo*.py,?at
py_library(
name = "mylib",
srcs = ["mylib.py"],
)
py_test(
name = "foo_bar",
srcs = ["foo_bar.py"],
)
py_test(
name = "cat",
srcs = ["cat.py"],
)
py_test(
name = "hat",
srcs = ["hat.py"],
)
```
### Notes
Resetting to the default value (such as in a subpackage) is manual. Set:
```starlark
# gazelle:python_test_file_pattern *_test.py,test_*.py
```
There currently is no way to tell gazelle that _no_ files in a package should
be mapped to {bzl:obj}`py_test` targets (see {gh-issue}`1826`). The workaround
is to set this directive to a pattern that will never match a `.py` file, such
as `foo.bar`:
```starlark
# No files in this package should be mapped to py_test targets.
# gazelle:python_test_file_pattern foo.bar
py_library(
name = "my_test",
srcs = ["my_test.py"],
)
```
## `python_label_convention`
:::{error}
Detailed docs are not yet written.
:::
## `python_label_normalization`
:::{error}
Detailed docs are not yet written.
:::
## `python_experimental_allow_relative_imports`
Enables experimental support for resolving relative imports in
`python_generation_mode package`.
By default, when `# gazelle:python_generation_mode package` is enabled,
relative imports (e.g., `from .library import foo`) are not added to the
deps field of the generated target. This results in incomplete {bzl:obj}`py_library`
rules that lack required dependencies on sibling packages.
Example:
Given this Python file import:
```python
from .library import add as _add
from .library import subtract as _subtract
```
Expected BUILD file output:
```starlark
py_library(
name = "py_default_library",
srcs = ["__init__.py"],
deps = [
"//example/library:py_default_library",
],
visibility = ["//visibility:public"],
)
```
Actual output without this annotation:
```starlark
py_library(
name = "py_default_library",
srcs = ["__init__.py"],
visibility = ["//visibility:public"],
)
```
If the directive is set to `true`, gazelle will resolve imports
that are relative to the current package.
## `python_generate_pyi_deps`
:::{error}
Detailed docs are not yet written.
:::
## `python_generate_proto`
When `# gazelle:python_generate_proto true`, Gazelle will generate one
{bzl:obj}`py_proto_library` for each {bzl:obj}`proto_library`, generating Python clients for
protobuf in each package. By default this is turned off. Gazelle will also
generate a load statement for the {bzl:obj}`py_proto_library` - attempting to detect
the configured name for the `@protobuf` / `@com_google_protobuf` repo in your
`MODULE.bazel`, and otherwise falling back to `@com_google_protobuf` for
compatibility with `WORKSPACE`.
:::{note}
In order to use this, you must manually configure Gazelle to target multiple
languages. Place this in your root `BUILD.bazel` file:
```
load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary")
gazelle_binary(
name = "gazelle_multilang",
languages = [
"@bazel_gazelle//language/proto",
# The python gazelle plugin must be listed _after_ the proto language.
"@rules_python_gazelle_plugin//python",
],
)
gazelle(
name = "gazelle",
gazelle = "//:gazelle_multilang",
)
```
:::
For example, in a package with `# gazelle:python_generate_proto true` and a
`foo.proto`, if you have both the proto extension and the Python extension
loaded into Gazelle, you'll get something like:
```starlark
load("@protobuf//bazel:py_proto_library.bzl", "py_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")
# gazelle:python_generate_proto true
proto_library(
name = "foo_proto",
srcs = ["foo.proto"],
visibility = ["//:__subpackages__"],
)
py_proto_library(
name = "foo_py_pb2",
visibility = ["//:__subpackages__"],
deps = [":foo_proto"],
)
```
When `false`, Gazelle will ignore any {bzl:obj}`py_proto_library`, including
previously-generated or hand-created rules.
## `python_resolve_sibling_imports`
:::{error}
Detailed docs are not yet written.
:::