Skip to content

docs(gazelle): Migrate Gazelle docs to ReadTheDocs, part 2/5: installation and usage #3132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 0 additions & 139 deletions gazelle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,145 +6,6 @@ ReadTheDocs. Please see https://rules-python.readthedocs.io/gazelle/docs/index.h
:::


## Example

We have an example of using Gazelle with Python located [here](https://github.com/bazel-contrib/rules_python/tree/main/examples/bzlmod).
A fully-working example without using bzlmod is in [`examples/build_file_generation`](../examples/build_file_generation).

The following documentation covers using bzlmod.

## Adding Gazelle to your project

First, you'll need to add Gazelle to your `MODULE.bazel` file.
Get the current version of Gazelle from there releases here: https://github.com/bazelbuild/bazel-gazelle/releases/.


See the installation `MODULE.bazel` snippet on the Releases page:
https://github.com/bazel-contrib/rules_python/releases in order to configure rules_python.

You will also need to add the `bazel_dep` for configuration for `rules_python_gazelle_plugin`.

Here is a snippet of a `MODULE.bazel` file.

```starlark
# The following stanza defines the dependency rules_python.
bazel_dep(name = "rules_python", version = "0.22.0")

# The following stanza defines the dependency rules_python_gazelle_plugin.
# For typical setups you set the version.
bazel_dep(name = "rules_python_gazelle_plugin", version = "0.22.0")

# The following stanza defines the dependency gazelle.
bazel_dep(name = "gazelle", version = "0.31.0", repo_name = "bazel_gazelle")

# Import the python repositories generated by the given module extension into the scope of the current module.
use_repo(python, "python3_9")
use_repo(python, "python3_9_toolchains")

# Register an already-defined toolchain so that Bazel can use it during toolchain resolution.
register_toolchains(
"@python3_9_toolchains//:all",
)

# Use the pip extension
pip = use_extension("@rules_python//python:extensions.bzl", "pip")

# Use the extension to call the `pip_repository` rule that invokes `pip`, with `incremental` set.
# Accepts a locked/compiled requirements file and installs the dependencies listed within.
# Those dependencies become available in a generated `requirements.bzl` file.
# You can instead check this `requirements.bzl` file into your repo.
# Because this project has different requirements for windows vs other
# operating systems, we have requirements for each.
pip.parse(
name = "pip",
requirements_lock = "//:requirements_lock.txt",
requirements_windows = "//:requirements_windows.txt",
)

# Imports the pip toolchain generated by the given module extension into the scope of the current module.
use_repo(pip, "pip")
```
Next, we'll fetch metadata about your Python dependencies, so that gazelle can
determine which package a given import statement comes from. This is provided
by the `modules_mapping` rule. We'll make a target for consuming this
`modules_mapping`, and writing it as a manifest file for Gazelle to read.
This is checked into the repo for speed, as it takes some time to calculate
in a large monorepo.

Gazelle will walk up the filesystem from a Python file to find this metadata,
looking for a file called `gazelle_python.yaml` in an ancestor folder of the Python code.
Create an empty file with this name. It might be next to your `requirements.txt` file.
(You can just use `touch` at this point, it just needs to exist.)

To keep the metadata updated, put this in your `BUILD.bazel` file next to `gazelle_python.yaml`:

```starlark
load("@pip//:requirements.bzl", "all_whl_requirements")
load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest")
load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")

# This rule fetches the metadata for python packages we depend on. That data is
# required for the gazelle_python_manifest rule to update our manifest file.
modules_mapping(
name = "modules_map",
wheels = all_whl_requirements,
)

# Gazelle python extension needs a manifest file mapping from
# an import to the installed package that provides it.
# This macro produces two targets:
# - //:gazelle_python_manifest.update can be used with `bazel run`
# to recalculate the manifest
# - //:gazelle_python_manifest.test is a test target ensuring that
# the manifest doesn't need to be updated
gazelle_python_manifest(
name = "gazelle_python_manifest",
modules_mapping = ":modules_map",
# This is what we called our `pip_parse` rule, where third-party
# python libraries are loaded in BUILD files.
pip_repository_name = "pip",
# This should point to wherever we declare our python dependencies
# (the same as what we passed to the modules_mapping rule in WORKSPACE)
# This argument is optional. If provided, the `.test` target is very
# fast because it just has to check an integrity field. If not provided,
# the integrity field is not added to the manifest which can help avoid
# merge conflicts in large repos.
requirements = "//:requirements_lock.txt",
# include_stub_packages: bool (default: False)
# If set to True, this flag automatically includes any corresponding type stub packages
# for the third-party libraries that are present and used. For example, if you have
# `boto3` as a dependency, and this flag is enabled, the corresponding `boto3-stubs`
# package will be automatically included in the BUILD file.
#
# Enabling this feature helps ensure that type hints and stubs are readily available
# for tools like type checkers and IDEs, improving the development experience and
# reducing manual overhead in managing separate stub packages.
include_stub_packages = True
)
```

Finally, you create a target that you'll invoke to run the Gazelle tool
with the rules_python extension included. This typically goes in your root
`/BUILD.bazel` file:

```starlark
load("@bazel_gazelle//:def.bzl", "gazelle")

# Our gazelle target points to the python gazelle binary.
# This is the simple case where we only need one language supported.
# If you also had proto, go, or other gazelle-supported languages,
# you would also need a gazelle_binary rule.
# See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example
gazelle(
name = "gazelle",
gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary",
)
```

That's it, now you can finally run `bazel run //:gazelle` anytime
you edit Python code, and it should update your `BUILD` files correctly.


### Directives

You can configure the extension using directives, just like for other
Expand Down
1 change: 1 addition & 0 deletions gazelle/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ the `update` command (the default) does anything for Python code.

```{toctree}
:maxdepth: 1
installation_and_usage
```
151 changes: 151 additions & 0 deletions gazelle/docs/installation_and_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Installation and Usage

## Example

Examples of using Gazelle with Python can be found in the `rules_python`
repo:

* bzlmod: {gh-path}`examples/bzlmod_build_file_generation`
* WORKSPACE: {gh-path}`examples/build_file_generation`

:::{note}
The following documentation covers using bzlmod.
:::


## Adding Gazelle to your project

First, you'll need to add Gazelle to your `MODULE.bazel` file. Get the current
version of [Gazelle][bcr-gazelle] from the [Bazel Central Registry][bcr]. Then
do the same for [`rules_python`][bcr-rules-python] and
[`rules_python_gazelle_plugin`][bcr-rules-python-gazelle-plugin].

[bcr-gazelle]: https://registry.bazel.build/modules/gazelle
[bcr]: https://registry.bazel.build/
[bcr-rules-python]: https://registry.bazel.build/modules/rules_python
[bcr-rules-python-gazelle-plugin]: https://registry.bazel.build/modules/rules_python_gazelle_plugin

Here is a snippet of a `MODULE.bazel` file. Note that most of it is just
general config for `rules_python` itself - the Gazelle plugin is only two lines
at the end.

```starlark
################################################
## START rules_python CONFIG ##
## See the main rules_python docs for details ##
################################################
bazel_dep(name = "rules_python", version = "1.5.1")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(python_version = "3.12.2")
use_repo(python, "python_3_12_2")

pip = use_extension("@rules_python//python:extensions.bzl", "pip")
pip.parse(
hub_name = "pip",
requirements_lock = "//:requirements_lock.txt",
requirements_windows = "//:requirements_windows.txt",
)
use_repo(pip, "pip")

##############################################
## START rules_python_gazelle_plugin CONFIG ##
##############################################

# The Gazelle plugin depends on Gazelle.
bazel_dep(name = "gazelle", version = "0.33.0", repo_name = "bazel_gazelle")

# Typically rules_python_gazelle_plugin is version matched to rules_python.
bazel_dep(name = "rules_python_gazelle_plugin", version = "1.5.1")
```

Next, we'll fetch metadata about your Python dependencies, so that gazelle can
determine which package a given import statement comes from. This is provided
by the `modules_mapping` rule. We'll make a target for consuming this
`modules_mapping`, and writing it as a manifest file for Gazelle to read.
This is checked into the repo for speed, as it takes some time to calculate
in a large monorepo.

Gazelle will walk up the filesystem from a Python file to find this metadata,
looking for a file called `gazelle_python.yaml` in an ancestor folder
of the Python code. Create an empty file with this name. It might be next
to your `requirements.txt` file. (You can just use {command}`touch` at
this point, it just needs to exist.)

To keep the metadata updated, put this in your `BUILD.bazel` file next
to `gazelle_python.yaml`:

```starlark
# `@pip` is the hub_name from pip.parse in MODULE.bazel.
load("@pip//:requirements.bzl", "all_whl_requirements")
load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest")
load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")

# This rule fetches the metadata for python packages we depend on. That data is
# required for the gazelle_python_manifest rule to update our manifest file.
modules_mapping(
name = "modules_map",
wheels = all_whl_requirements,
)

# Gazelle python extension needs a manifest file mapping from
# an import to the installed package that provides it.
# This macro produces two targets:
# - //:gazelle_python_manifest.update can be used with `bazel run`
# to recalculate the manifest
# - //:gazelle_python_manifest.test is a test target ensuring that
# the manifest doesn't need to be updated
gazelle_python_manifest(
name = "gazelle_python_manifest",
modules_mapping = ":modules_map",

# This is what we called our `pip.parse` rule in MODULE.bazel, where third-party
# python libraries are loaded in BUILD files.
pip_repository_name = "pip",

# This should point to wherever we declare our python dependencies
# (the same as what we passed to the modules_mapping rule in WORKSPACE)
# This argument is optional. If provided, the `.test` target is very
# fast because it just has to check an integrity field. If not provided,
# the integrity field is not added to the manifest which can help avoid
# merge conflicts in large repos.
requirements = "//:requirements_lock.txt",

# include_stub_packages: bool (default: False)
# If set to True, this flag automatically includes any corresponding type stub packages
# for the third-party libraries that are present and used. For example, if you have
# `boto3` as a dependency, and this flag is enabled, the corresponding `boto3-stubs`
# package will be automatically included in the BUILD file.
# Enabling this feature helps ensure that type hints and stubs are readily available
# for tools like type checkers and IDEs, improving the development experience and
# reducing manual overhead in managing separate stub packages.
include_stub_packages = True
)
```

Finally, you create a target that you'll invoke to run the Gazelle tool
with the `rules_python` extension included. This typically goes in your root
`/BUILD.bazel` file:

```starlark
load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary")

gazelle_binary(
name = "gazelle_multilang",
languages = [
# List of language plugins.
# If you want to generate py_proto_library targets PR #3057), then
# the proto language plugin _must_ come before the rules_python plugin.
#"@bazel_gazelle//lanugage/proto",
"@rules_python_gazelle_plugin//python",
],
)

gazelle(
name = "gazelle",
gazelle = ":gazelle_multilang",
)
```

That's it, now you can finally run `bazel run //:gazelle` anytime
you edit Python code, and it should update your `BUILD` files correctly.