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 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.
The Python-specific directives are:
{.glossary} # gazelle:python_extension value
: Controls whether the Python extension is enabled or not. Sub-packages inherit this value.
enabled
enabled
, disabled
# gazelle: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.
# gazelle:python_manifest_file_name value
: Overrides the default manifest file name.
gazelle_python.yaml
# gazelle:python_ignore_files value
: Controls the files which are ignored from the generated targets.
# gazelle:python_ignore_dependencies value
: Controls the ignored dependencies from the generated targets.
# gazelle:python_validate_import_statements bool
: Controls whether the Python import statements should be validated.
true
true
, false
# gazelle:python_generation_mode value
: Controls the target generation mode.
package
file
, package
, project
# gazelle:python_generation_mode_per_file_include_init bool
: Controls whether __init__.py
files are included as srcs in each generated target when target generation mode is “file”.
false
true
, false
# gazelle:python_generation_mode_per_package_require_test_entry_point bool
: Controls whether a file called __test__.py
or a target called __test__
is required to generate one test target per package in package mode.
true
true
, false
# gazelle:python_library_naming_convention value
: 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
.
$package_name$
"$package_name$"
# gazelle:python_binary_naming_convention value
: Controls the {bzl:obj}py_binary
naming convention. Follows the same interpolation rules as python_library_naming_convention
.
$package_name$_bin
"$package_name$"
# gazelle:python_test_naming_convention value
: Controls the {bzl:obj}py_test
naming convention. Follows the same interpolation rules as python_library_naming_convention
.
$package_name$_test
"$package_name$"
# gazelle:python_proto_naming_convention value
: 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
.
$proto_name$_py_pb2
"$proto_name$"
# gazelle:resolve py import-lang import-string label
: 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
.
# gazelle:python_default_visibility labels
: Instructs gazelle to use these visibility labels on all python targets. labels
is a comma-separated list of labels (without spaces).
//$python_root$:__subpackages__
# gazelle:python_visibility label
: Appends additional visibility labels to each generated target. This r directive can be set multiple times.
# gazelle:python_test_file_pattern value
: Filenames matching these comma-separated {command}glob
s will be mapped to {bzl:obj}py_test
targets.
*_test.py,test_*.py
# gazelle:python_label_convention value
: 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")
.
$distribution_name$
# gazelle:python_label_normalization value
: 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).
snake_case
snake_case
, none
, pep503
# gazelle:python_experimental_allow_relative_imports bool
: Controls whether Gazelle resolves dependencies for import statements that use paths relative to the current package.
false
true
, false
# gazelle:python_generate_pyi_deps bool
: 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.
false
true
, false
# gazelle:python_generate_proto bool
: 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.
false
true
, false
# gazelle:python_resolve_sibling_imports bool
: Allows absolute imports to be resolved to sibling modules (Python 2's behavior without absolute_import
).
false
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), then set this directive in src/BUILD.bazel
:
# ./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:
# in ./src/foo/BUILD.bazel py_libary( ... imports = [".."], # Gazelle adds this ... ) # in ./src/foo/bar/BUILD.bazel py_libary( ... imports = ["../.."], # Gazelle adds this ... )
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:
srcs
with the same name as the {bzl:obj}py_test
target, ormain
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: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:
# 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:
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, so by default in the above example Gazelle would generate foo_pb2_py
. Any pre-existing rules are left in place and not renamed.
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:
# gazelle:python_default_visibility //:__subpackages__,//tests:__subpackages__
produces the following visibility attribute:
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.
# 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:
# gazelle:python_default_visibility NONE py_library( name = "...", srcs = [...], )
# 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.
# ./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:
# ./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.
# 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.
*_test.py,test_*.py
: both test_*.py
and *_test.py
files will generate {bzl:obj}py_test
targets..py
extension in the {command}glob
: foo*.py,?at.py
.glob
patterns, separated by commas without spaces:# 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"], )
Resetting to the default value (such as in a subpackage) is manual. Set:
# 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
:
# 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:
from .library import add as _add from .library import subtract as _subtract
Expected BUILD file output:
py_library( name = "py_default_library", srcs = ["__init__.py"], deps = [ "//example/library:py_default_library", ], visibility = ["//visibility:public"], )
Actual output without this annotation:
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:
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. :::