|
| 1 | +# Installation and Usage |
| 2 | + |
| 3 | +## Example |
| 4 | + |
| 5 | +Examples of using Gazelle with Python can be found in the `rules_python` |
| 6 | +repo: |
| 7 | + |
| 8 | +* bzlmod: {gh-path}`examples/bzlmod_build_file_generation` |
| 9 | +* WORKSPACE: {gh-path}`examples/build_file_generation` |
| 10 | + |
| 11 | +:::{note} |
| 12 | +The following documentation covers using bzlmod. |
| 13 | +::: |
| 14 | + |
| 15 | + |
| 16 | +## Adding Gazelle to your project |
| 17 | + |
| 18 | +First, you'll need to add Gazelle to your `MODULE.bazel` file. Get the current |
| 19 | +version of Gazelle from their [releases page][gazelle-releases]. |
| 20 | + |
| 21 | +[gazelle-releases]: https://github.com/bazel-contrib/bazel-gazelle/releases/ |
| 22 | + |
| 23 | +See the installation `MODULE.bazel` snippet on the `rules_python` |
| 24 | +[releases page][rules-python-releases] in order to configure `rules_python`. |
| 25 | + |
| 26 | +[rules-python-releases]: https://github.com/bazel-contrib/rules_python/releases |
| 27 | + |
| 28 | +You will also need to add the {bzl:obj}`bazel_dep` for configuration for |
| 29 | +`rules_python_gazelle_plugin`. |
| 30 | + |
| 31 | +Here is a snippet of a `MODULE.bazel` file. |
| 32 | + |
| 33 | +```starlark |
| 34 | +# The following stanza defines the dependency rules_python. |
| 35 | +bazel_dep(name = "rules_python", version = "0.22.0") |
| 36 | + |
| 37 | +# The following stanza defines the dependency rules_python_gazelle_plugin. |
| 38 | +# For typical setups you set the version. |
| 39 | +bazel_dep(name = "rules_python_gazelle_plugin", version = "0.22.0") |
| 40 | + |
| 41 | +# The following stanza defines the dependency gazelle. |
| 42 | +bazel_dep(name = "gazelle", version = "0.31.0", repo_name = "bazel_gazelle") |
| 43 | + |
| 44 | +# Import the python repositories generated by the given module extension into |
| 45 | +# the scope of the current module. |
| 46 | +use_repo(python, "python3_9") |
| 47 | +use_repo(python, "python3_9_toolchains") |
| 48 | + |
| 49 | +# Register an already-defined toolchain so that Bazel can use it during |
| 50 | +# toolchain resolution. |
| 51 | +register_toolchains( |
| 52 | + "@python3_9_toolchains//:all", |
| 53 | +) |
| 54 | + |
| 55 | +# Use the pip extension |
| 56 | +pip = use_extension("@rules_python//python:extensions.bzl", "pip") |
| 57 | + |
| 58 | +# Use the extension to call the `pip_repository` rule that invokes `pip`, with |
| 59 | +# `incremental` set. |
| 60 | +# Accepts a locked/compiled requirements file and installs the dependencies listed within. |
| 61 | +# Those dependencies become available in a generated `requirements.bzl` file. |
| 62 | +# You can instead check this `requirements.bzl` file into your repo. |
| 63 | +# Because this project has different requirements for windows vs other |
| 64 | +# operating systems, we have requirements for each. |
| 65 | +pip.parse( |
| 66 | + name = "pip", |
| 67 | + requirements_lock = "//:requirements_lock.txt", |
| 68 | + requirements_windows = "//:requirements_windows.txt", |
| 69 | +) |
| 70 | + |
| 71 | +# Imports the pip toolchain generated by the given module extension into the |
| 72 | +# scope of the current module. |
| 73 | +use_repo(pip, "pip") |
| 74 | +``` |
| 75 | + |
| 76 | +Next, we'll fetch metadata about your Python dependencies, so that gazelle can |
| 77 | +determine which package a given import statement comes from. This is provided |
| 78 | +by the {bzl:obj}`modules_mapping` rule. We'll make a target for consuming this |
| 79 | +{bzl:obj}`modules_mapping`, and writing it as a manifest file for Gazelle to read. |
| 80 | +This is checked into the repo for speed, as it takes some time to calculate |
| 81 | +in a large monorepo. |
| 82 | + |
| 83 | +Gazelle will walk up the filesystem from a Python file to find this metadata, |
| 84 | +looking for a file called `gazelle_python.yaml` in an ancestor folder |
| 85 | +of the Python code. Create an empty file with this name. It might be next |
| 86 | +to your `requirements.txt` file. (You can just use {command}`touch` at |
| 87 | +this point, it just needs to exist.) |
| 88 | + |
| 89 | +To keep the metadata updated, put this in your `BUILD.bazel` file next |
| 90 | +to `gazelle_python.yaml`: |
| 91 | + |
| 92 | +```starlark |
| 93 | +load("@pip//:requirements.bzl", "all_whl_requirements") |
| 94 | +load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest") |
| 95 | +load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping") |
| 96 | + |
| 97 | +# This rule fetches the metadata for python packages we depend on. That data is |
| 98 | +# required for the gazelle_python_manifest rule to update our manifest file. |
| 99 | +modules_mapping( |
| 100 | + name = "modules_map", |
| 101 | + wheels = all_whl_requirements, |
| 102 | +) |
| 103 | + |
| 104 | +# Gazelle python extension needs a manifest file mapping from |
| 105 | +# an import to the installed package that provides it. |
| 106 | +# This macro produces two targets: |
| 107 | +# - //:gazelle_python_manifest.update can be used with `bazel run` |
| 108 | +# to recalculate the manifest |
| 109 | +# - //:gazelle_python_manifest.test is a test target ensuring that |
| 110 | +# the manifest doesn't need to be updated |
| 111 | +gazelle_python_manifest( |
| 112 | + name = "gazelle_python_manifest", |
| 113 | + modules_mapping = ":modules_map", |
| 114 | + # This is what we called our `pip_parse` rule, where third-party |
| 115 | + # python libraries are loaded in BUILD files. |
| 116 | + pip_repository_name = "pip", |
| 117 | + # This should point to wherever we declare our python dependencies |
| 118 | + # (the same as what we passed to the modules_mapping rule in WORKSPACE) |
| 119 | + # This argument is optional. If provided, the `.test` target is very |
| 120 | + # fast because it just has to check an integrity field. If not provided, |
| 121 | + # the integrity field is not added to the manifest which can help avoid |
| 122 | + # merge conflicts in large repos. |
| 123 | + requirements = "//:requirements_lock.txt", |
| 124 | + # include_stub_packages: bool (default: False) |
| 125 | + # If set to True, this flag automatically includes any corresponding type stub packages |
| 126 | + # for the third-party libraries that are present and used. For example, if you have |
| 127 | + # `boto3` as a dependency, and this flag is enabled, the corresponding `boto3-stubs` |
| 128 | + # package will be automatically included in the BUILD file. |
| 129 | + # |
| 130 | + # Enabling this feature helps ensure that type hints and stubs are readily available |
| 131 | + # for tools like type checkers and IDEs, improving the development experience and |
| 132 | + # reducing manual overhead in managing separate stub packages. |
| 133 | + include_stub_packages = True |
| 134 | +) |
| 135 | +``` |
| 136 | + |
| 137 | +Finally, you create a target that you'll invoke to run the Gazelle tool |
| 138 | +with the `rules_python` extension included. This typically goes in your root |
| 139 | +`/BUILD.bazel` file: |
| 140 | + |
| 141 | +```starlark |
| 142 | +load("@bazel_gazelle//:def.bzl", "gazelle") |
| 143 | + |
| 144 | +# Our gazelle target points to the python gazelle binary. |
| 145 | +# This is the simple case where we only need one language supported. |
| 146 | +# If you also had proto, go, or other gazelle-supported languages, |
| 147 | +# you would also need a gazelle_binary rule. |
| 148 | +# See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example |
| 149 | +gazelle( |
| 150 | + name = "gazelle", |
| 151 | + gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary", |
| 152 | +) |
| 153 | +``` |
| 154 | + |
| 155 | +That's it, now you can finally run `bazel run //:gazelle` anytime |
| 156 | +you edit Python code, and it should update your `BUILD` files correctly. |
0 commit comments