• Home
Name Date Size #Lines LOC

..--

.bazelci/06-Sep-2024-601528

.bcr/06-Sep-2024-12677

.ci/06-Sep-2024-109

.github/06-Sep-2024-437256

docs/06-Sep-2024-1,265873

examples/06-Sep-2024-8,5717,137

gazelle/06-Sep-2024-11,1126,679

proposals/06-Sep-2024-445276

python/06-Sep-2024-10,3698,603

tests/06-Sep-2024-2,9502,482

tools/06-Sep-2024-3,2072,678

.bazelignoreD06-Sep-2024447 1211

.bazelrcD06-Sep-20242.8 KiB2218

.bazelversionD06-Sep-20246 21

.git-blame-ignore-revsD06-Sep-202482 32

.gitattributesD06-Sep-202478 32

.gitignoreD06-Sep-2024428 4838

.pre-commit-config.yamlD06-Sep-20241.6 KiB4829

AUTHORSD06-Sep-2024305 107

BUILD.bazelD06-Sep-20242.4 KiB8879

BZLMOD_SUPPORT.mdD06-Sep-20243 KiB6240

CHANGELOG.mdD06-Sep-20243 KiB8159

CONTRIBUTING.mdD06-Sep-20247.1 KiB206146

CONTRIBUTORSD06-Sep-2024477 1311

DEVELOPING.mdD06-Sep-20242.2 KiB5136

LICENSED06-Sep-202411.1 KiB202169

METADATAD06-Sep-2024330 1615

MODULE.bazelD06-Sep-20241.6 KiB5245

MODULE_LICENSE_APACHE2D06-Sep-20240

OWNERSD06-Sep-202430 31

README.mdD06-Sep-202414.8 KiB381272

WORKSPACED06-Sep-20243 KiB8969

addlicense.shD06-Sep-2024869 246

internal_deps.bzlD06-Sep-20248.2 KiB185166

internal_setup.bzlD06-Sep-20241.5 KiB3930

renovate.jsonD06-Sep-202449 65

version.bzlD06-Sep-20241.5 KiB4035

README.md

1# Python Rules for Bazel
2
3[![Build status](https://badge.buildkite.com/1bcfe58b6f5741aacb09b12485969ba7a1205955a45b53e854.svg?branch=main)](https://buildkite.com/bazel/python-rules-python-postsubmit)
4
5## Overview
6
7This repository is the home of the core Python rules -- `py_library`,
8`py_binary`, `py_test`, `py_proto_library`, and related symbols that provide the basis for Python
9support in Bazel. It also contains package installation rules for integrating with PyPI and other indices.
10
11Documentation for rules_python  lives in the
12[`docs/`](https://github.com/bazelbuild/rules_python/tree/main/docs)
13directory and in the
14[Bazel Build Encyclopedia](https://docs.bazel.build/versions/master/be/python.html).
15
16Examples live in the [examples](examples) directory.
17
18Currently, the core rules build into the Bazel binary, and the symbols in this
19repository are simple aliases. However, we are migrating the rules to Starlark and removing them from the Bazel binary. Therefore, the future-proof way to depend on Python rules is via this repository. See[`Migrating from the Bundled Rules`](#Migrating-from-the-bundled-rules) below.
20
21The core rules are stable. Their implementation in Bazel is subject to Bazel's
22[backward compatibility policy](https://docs.bazel.build/versions/master/backward-compatibility.html).
23Once migrated to rules_python, they may evolve at a different
24rate, but this repository will still follow [semantic versioning](https://semver.org).
25
26The Bazel community maintains this repository. Neither Google nor the Bazel team provides support for the code. However, this repository is part of the test suite used to vet new Bazel releases. See [How to contribute](CONTRIBUTING.md) page for information on our development workflow.
27
28## Bzlmod support
29
30- Status: Beta
31- Full Feature Parity: No
32
33See [Bzlmod support](BZLMOD_SUPPORT.md) for more details.
34
35## Getting started
36
37The following two sections cover using `rules_python` with bzlmod and
38the older way of configuring bazel with a `WORKSPACE` file.
39
40### Using bzlmod
41
42**IMPORTANT: bzlmod support is still in Beta; APIs are subject to change.**
43
44The first step to using rules_python with bzlmod is to add the dependency to
45your MODULE.bazel file:
46
47```starlark
48# Update the version "0.0.0" to the release found here:
49# https://github.com/bazelbuild/rules_python/releases.
50bazel_dep(name = "rules_python", version = "0.0.0")
51```
52
53Once added, you can load the rules and use them:
54
55```starlark
56load("@rules_python//python:py_binary.bzl", "py_binary")
57
58py_binary(...)
59```
60
61Depending on what you're doing, you likely want to do some additional
62configuration to control what Python version is used; read the following
63sections for how to do that.
64
65#### Toolchain registration with bzlmod
66
67A default toolchain is automatically configured depending on
68`rules_python`. Note, however, the version used tracks the most recent Python
69release and will change often.
70
71If you want to use a specific Python version for your programs, then how
72to do so depends on if you're configuring the root module or not. The root
73module is special because it can set the *default* Python version, which
74is used by the version-unaware rules (e.g. `//python:py_binary.bzl` et al). For
75submodules, it's recommended to use the version-aware rules to pin your programs
76to a specific Python version so they don't accidentally run with a different
77version configured by the root module.
78
79##### Configuring and using the default Python version
80
81To specify what the default Python version is, set `is_default = True` when
82calling `python.toolchain()`. This can only be done by the root module; it is
83silently ignored if a submodule does it. Similarly, using the version-unaware
84rules (which always use the default Python version) should only be done by the
85root module. If submodules use them, then they may run with a different Python
86version than they expect.
87
88```starlark
89python = use_extension("@rules_python//python/extensions:python.bzl", "python")
90
91python.toolchain(
92    python_version = "3.11",
93    is_default = True,
94)
95```
96
97Then use the base rules from e.g. `//python:py_binary.bzl`.
98
99##### Pinning to a Python version
100
101Pinning to a version allows targets to force that a specific Python version is
102used, even if the root module configures a different version as a default. This
103is most useful for two cases:
104
1051. For submodules to ensure they run with the appropriate Python version
1062. To allow incremental, per-target, upgrading to newer Python versions,
107   typically in a mono-repo situation.
108
109To configure a submodule with the version-aware rules, request the particular
110version you need, then use the `@python_versions` repo to use the rules that
111force specific versions:
112
113```starlark
114python = use_extension("@rules_python//python/extensions:python.bzl", "python")
115
116python.toolchain(
117    python_version = "3.11",
118)
119use_repo(python, "python_versions")
120```
121
122Then use e.g. `load("@python_versions//3.11:defs.bzl", "py_binary")` to use
123the rules that force that particular version. Multiple versions can be specified
124and use within a single build.
125
126For more documentation, see the bzlmod examples under the [examples](examples) folder.  Look for the examples that contain a `MODULE.bazel` file.
127
128##### Other toolchain details
129
130The `python.toolchain()` call makes its contents available under a repo named
131`python_X_Y`, where X and Y are the major and minor versions. For example,
132`python.toolchain(python_version="3.11")` creates the repo `@python_3_11`.
133Remember to call `use_repo()` to make repos visible to your module:
134`use_repo(python, "python_3_11")`
135
136### Using a WORKSPACE file
137
138To import rules_python in your project, you first need to add it to your
139`WORKSPACE` file, using the snippet provided in the
140[release you choose](https://github.com/bazelbuild/rules_python/releases)
141
142To depend on a particular unreleased version, you can do the following:
143
144```starlark
145load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
146
147
148# Update the SHA and VERSION to the lastest version available here:
149# https://github.com/bazelbuild/rules_python/releases.
150
151SHA="84aec9e21cc56fbc7f1335035a71c850d1b9b5cc6ff497306f84cced9a769841"
152
153VERSION="0.23.1"
154
155http_archive(
156    name = "rules_python",
157    sha256 = SHA,
158    strip_prefix = "rules_python-{}".format(VERSION),
159    url = "https://github.com/bazelbuild/rules_python/releases/download/{}/rules_python-{}.tar.gz".format(VERSION,VERSION),
160)
161
162load("@rules_python//python:repositories.bzl", "py_repositories")
163
164py_repositories()
165```
166
167#### Toolchain registration
168
169To register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `WORKSPACE` file:
170
171```starlark
172load("@rules_python//python:repositories.bzl", "python_register_toolchains")
173
174python_register_toolchains(
175    name = "python_3_11",
176    # Available versions are listed in @rules_python//python:versions.bzl.
177    # We recommend using the same version your team is already standardized on.
178    python_version = "3.11",
179)
180
181load("@python_3_11//:defs.bzl", "interpreter")
182
183load("@rules_python//python:pip.bzl", "pip_parse")
184
185pip_parse(
186    ...
187    python_interpreter_target = interpreter,
188    ...
189)
190```
191
192After registration, your Python targets will use the toolchain's interpreter during execution, but a system-installed interpreter
193is still used to 'bootstrap' Python targets (see https://github.com/bazelbuild/rules_python/issues/691).
194You may also find some quirks while using this toolchain. Please refer to [python-build-standalone documentation's _Quirks_ section](https://python-build-standalone.readthedocs.io/en/latest/quirks.html).
195
196### Toolchain usage in other rules
197
198Python toolchains can be utilized in other bazel rules, such as `genrule()`, by adding the `toolchains=["@rules_python//python:current_py_toolchain"]` attribute. You can obtain the path to the Python interpreter using the `$(PYTHON2)` and `$(PYTHON3)` ["Make" Variables](https://bazel.build/reference/be/make-variables). See the [`test_current_py_toolchain`](tests/load_from_macro/BUILD.bazel) target for an example.
199
200### "Hello World"
201
202Once you've imported the rule set into your `WORKSPACE` using any of these
203methods, you can then load the core rules in your `BUILD` files with the following:
204
205```starlark
206load("@rules_python//python:defs.bzl", "py_binary")
207
208py_binary(
209  name = "main",
210  srcs = ["main.py"],
211)
212```
213
214## Using dependencies from PyPI
215
216Using PyPI packages (aka "pip install") involves two main steps.
217
2181. [Installing third_party packages](#installing-third_party-packages)
2192. [Using third_party packages as dependencies](#using-third_party-packages-as-dependencies
220
221### Installing third_party packages
222
223#### Using bzlmod
224
225To add pip dependencies to your `MODULE.bazel` file, use the `pip.parse` extension, and call it to create the central external repo and individual wheel external repos. Include in the `MODULE.bazel` the toolchain extension as shown in the first bzlmod example above.
226
227```starlark
228pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
229pip.parse(
230    hub_name = "my_deps",
231    python_version = "3.11",
232    requirements_lock = "//:requirements_lock_3_11.txt",
233)
234use_repo(pip, "my_deps")
235```
236For more documentation, including how the rules can update/create a requirements file, see the bzlmod examples under the [examples](examples) folder.
237
238#### Using a WORKSPACE file
239
240To add pip dependencies to your `WORKSPACE`, load the `pip_parse` function and call it to create the central external repo and individual wheel external repos.
241
242```starlark
243load("@rules_python//python:pip.bzl", "pip_parse")
244
245# Create a central repo that knows about the dependencies needed from
246# requirements_lock.txt.
247pip_parse(
248   name = "my_deps",
249   requirements_lock = "//path/to:requirements_lock.txt",
250)
251# Load the starlark macro, which will define your dependencies.
252load("@my_deps//:requirements.bzl", "install_deps")
253# Call it to define repos for your requirements.
254install_deps()
255```
256
257#### pip rules
258
259Note that since `pip_parse` is a repository rule and therefore executes pip at WORKSPACE-evaluation time, Bazel has no
260information about the Python toolchain and cannot enforce that the interpreter
261used to invoke pip matches the interpreter used to run `py_binary` targets. By
262default, `pip_parse` uses the system command `"python3"`. To override this, pass in the
263`python_interpreter` attribute or `python_interpreter_target` attribute to `pip_parse`.
264
265You can have multiple `pip_parse`s in the same workspace.  Or use the pip extension multiple times when using bzlmod.
266This configuration will create multiple external repos that have no relation to one another
267and may result in downloading the same wheels numerous times.
268
269As with any repository rule, if you would like to ensure that `pip_parse` is
270re-executed to pick up a non-hermetic change to your environment (e.g.,
271updating your system `python` interpreter), you can force it to re-execute by running
272`bazel sync --only [pip_parse name]`.
273
274Note: The `pip_install` rule is deprecated. `pip_parse` offers identical functionality, and both `pip_install` and `pip_parse` now have the same implementation. The name `pip_install` may be removed in a future version of the rules.
275
276The maintainers have made all reasonable efforts to facilitate a smooth transition. Still, some users of `pip_install` will need to replace their existing `requirements.txt` with a fully resolved set of dependencies using a tool such as `pip-tools` or the `compile_pip_requirements` repository rule.
277
278### Using third_party packages as dependencies
279
280Each extracted wheel repo contains a `py_library` target representing
281the wheel's contents. There are two ways to access this library. The
282first uses the `requirement()` function defined in the central
283repo's `//:requirements.bzl` file. This function maps a pip package
284name to a label:
285
286```starlark
287load("@my_deps//:requirements.bzl", "requirement")
288
289py_library(
290    name = "mylib",
291    srcs = ["mylib.py"],
292    deps = [
293        ":myotherlib",
294        requirement("some_pip_dep"),
295        requirement("another_pip_dep"),
296    ]
297)
298```
299
300The reason `requirement()` exists is that the pattern for the labels,
301while not expected to change frequently, is not guaranteed to be
302stable. Using `requirement()` ensures you do not have to refactor
303your `BUILD` files if the pattern changes.
304
305On the other hand, using `requirement()` has several drawbacks; see
306[this issue][requirements-drawbacks] for an enumeration. If you don't
307want to use `requirement()`, you can use the library
308labels directly instead. For `pip_parse`, the labels are of the following form:
309
310```starlark
311@{name}_{package}//:pkg
312```
313
314Here `name` is the `name` attribute that was passed to `pip_parse` and
315`package` is the pip package name with characters that are illegal in
316Bazel label names (e.g. `-`, `.`) replaced with `_`. If you need to
317update `name` from "old" to "new", then you can run the following
318buildozer command:
319
320```shell
321buildozer 'substitute deps @old_([^/]+)//:pkg @new_${1}//:pkg' //...:*
322```
323
324For `pip_install`, the labels are instead of the form:
325
326```starlark
327@{name}//pypi__{package}
328```
329
330[requirements-drawbacks]: https://github.com/bazelbuild/rules_python/issues/414
331
332#### 'Extras' dependencies
333
334Any 'extras' specified in the requirements lock file will be automatically added as transitive dependencies of the package. In the example above, you'd just put `requirement("useful_dep")`.
335
336### Consuming Wheel Dists Directly
337
338If you need to depend on the wheel dists themselves, for instance, to pass them
339to some other packaging tool, you can get a handle to them with the `whl_requirement` macro. For example:
340
341```starlark
342filegroup(
343    name = "whl_files",
344    data = [
345        whl_requirement("boto3"),
346    ]
347)
348```
349# Python Gazelle plugin
350
351[Gazelle](https://github.com/bazelbuild/bazel-gazelle)
352is a build file generator for Bazel projects. It can create new `BUILD.bazel` files for a project that follows language conventions and update existing build files to include new sources, dependencies, and options.
353
354Bazel may run Gazelle using the Gazelle rule, or it may be installed and run as a command line tool.
355
356See the documentation for Gazelle with rules_python [here](gazelle).
357
358## Migrating from the bundled rules
359
360The core rules are currently available in Bazel as built-in symbols, but this
361form is deprecated. Instead, you should depend on rules_python in your
362`WORKSPACE` file and load the Python rules from
363`@rules_python//python:defs.bzl`.
364
365A [buildifier](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md)
366fix is available to automatically migrate `BUILD` and `.bzl` files to add the
367appropriate `load()` statements and rewrite uses of `native.py_*`.
368
369```sh
370# Also consider using the -r flag to modify an entire workspace.
371buildifier --lint=fix --warnings=native-py <files>
372```
373
374Currently, the `WORKSPACE` file needs to be updated manually as per [Getting
375started](#Getting-started) above.
376
377Note that Starlark-defined bundled symbols underneath
378`@bazel_tools//tools/python` are also deprecated. These are not yet rewritten
379by buildifier.
380
381