xref: /aosp_15_r20/external/bazelbuild-rules_python/docs/pypi-dependencies.md (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker:::{default-domain} bzl
2*60517a1eSAndroid Build Coastguard Worker:::
3*60517a1eSAndroid Build Coastguard Worker
4*60517a1eSAndroid Build Coastguard Worker# Using dependencies from PyPI
5*60517a1eSAndroid Build Coastguard Worker
6*60517a1eSAndroid Build Coastguard WorkerUsing PyPI packages (aka "pip install") involves two main steps.
7*60517a1eSAndroid Build Coastguard Worker
8*60517a1eSAndroid Build Coastguard Worker1. [Installing third party packages](#installing-third-party-packages)
9*60517a1eSAndroid Build Coastguard Worker2. [Using third party packages as dependencies](#using-third-party-packages)
10*60517a1eSAndroid Build Coastguard Worker
11*60517a1eSAndroid Build Coastguard Worker{#installing-third-party-packages}
12*60517a1eSAndroid Build Coastguard Worker## Installing third party packages
13*60517a1eSAndroid Build Coastguard Worker
14*60517a1eSAndroid Build Coastguard Worker### Using bzlmod
15*60517a1eSAndroid Build Coastguard Worker
16*60517a1eSAndroid Build Coastguard WorkerTo add pip dependencies to your `MODULE.bazel` file, use the `pip.parse`
17*60517a1eSAndroid Build Coastguard Workerextension, and call it to create the central external repo and individual wheel
18*60517a1eSAndroid Build Coastguard Workerexternal repos. Include in the `MODULE.bazel` the toolchain extension as shown
19*60517a1eSAndroid Build Coastguard Workerin the first bzlmod example above.
20*60517a1eSAndroid Build Coastguard Worker
21*60517a1eSAndroid Build Coastguard Worker```starlark
22*60517a1eSAndroid Build Coastguard Workerpip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
23*60517a1eSAndroid Build Coastguard Workerpip.parse(
24*60517a1eSAndroid Build Coastguard Worker    hub_name = "my_deps",
25*60517a1eSAndroid Build Coastguard Worker    python_version = "3.11",
26*60517a1eSAndroid Build Coastguard Worker    requirements_lock = "//:requirements_lock_3_11.txt",
27*60517a1eSAndroid Build Coastguard Worker)
28*60517a1eSAndroid Build Coastguard Workeruse_repo(pip, "my_deps")
29*60517a1eSAndroid Build Coastguard Worker```
30*60517a1eSAndroid Build Coastguard WorkerFor more documentation, including how the rules can update/create a requirements
31*60517a1eSAndroid Build Coastguard Workerfile, see the bzlmod examples under the {gh-path}`examples` folder or the documentation
32*60517a1eSAndroid Build Coastguard Workerfor the {obj}`@rules_python//python/extensions:pip.bzl` extension.
33*60517a1eSAndroid Build Coastguard Worker
34*60517a1eSAndroid Build Coastguard Worker```{note}
35*60517a1eSAndroid Build Coastguard WorkerWe are using a host-platform compatible toolchain by default to setup pip dependencies.
36*60517a1eSAndroid Build Coastguard WorkerDuring the setup phase, we create some symlinks, which may be inefficient on Windows
37*60517a1eSAndroid Build Coastguard Workerby default. In that case use the following `.bazelrc` options to improve performance if
38*60517a1eSAndroid Build Coastguard Workeryou have admin privileges:
39*60517a1eSAndroid Build Coastguard Worker
40*60517a1eSAndroid Build Coastguard Worker    startup --windows_enable_symlinks
41*60517a1eSAndroid Build Coastguard Worker
42*60517a1eSAndroid Build Coastguard WorkerThis will enable symlinks on Windows and help with bootstrap performance of setting up the
43*60517a1eSAndroid Build Coastguard Workerhermetic host python interpreter on this platform. Linux and OSX users should see no
44*60517a1eSAndroid Build Coastguard Workerdifference.
45*60517a1eSAndroid Build Coastguard Worker```
46*60517a1eSAndroid Build Coastguard Worker
47*60517a1eSAndroid Build Coastguard Worker### Using a WORKSPACE file
48*60517a1eSAndroid Build Coastguard Worker
49*60517a1eSAndroid Build Coastguard WorkerTo add pip dependencies to your `WORKSPACE`, load the `pip_parse` function and
50*60517a1eSAndroid Build Coastguard Workercall it to create the central external repo and individual wheel external repos.
51*60517a1eSAndroid Build Coastguard Worker
52*60517a1eSAndroid Build Coastguard Worker```starlark
53*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:pip.bzl", "pip_parse")
54*60517a1eSAndroid Build Coastguard Worker
55*60517a1eSAndroid Build Coastguard Worker# Create a central repo that knows about the dependencies needed from
56*60517a1eSAndroid Build Coastguard Worker# requirements_lock.txt.
57*60517a1eSAndroid Build Coastguard Workerpip_parse(
58*60517a1eSAndroid Build Coastguard Worker   name = "my_deps",
59*60517a1eSAndroid Build Coastguard Worker   requirements_lock = "//path/to:requirements_lock.txt",
60*60517a1eSAndroid Build Coastguard Worker)
61*60517a1eSAndroid Build Coastguard Worker# Load the starlark macro, which will define your dependencies.
62*60517a1eSAndroid Build Coastguard Workerload("@my_deps//:requirements.bzl", "install_deps")
63*60517a1eSAndroid Build Coastguard Worker# Call it to define repos for your requirements.
64*60517a1eSAndroid Build Coastguard Workerinstall_deps()
65*60517a1eSAndroid Build Coastguard Worker```
66*60517a1eSAndroid Build Coastguard Worker
67*60517a1eSAndroid Build Coastguard Worker(vendoring-requirements)=
68*60517a1eSAndroid Build Coastguard Worker#### Vendoring the requirements.bzl file
69*60517a1eSAndroid Build Coastguard Worker
70*60517a1eSAndroid Build Coastguard WorkerIn some cases you may not want to generate the requirements.bzl file as a repository rule
71*60517a1eSAndroid Build Coastguard Workerwhile Bazel is fetching dependencies. For example, if you produce a reusable Bazel module
72*60517a1eSAndroid Build Coastguard Workersuch as a ruleset, you may want to include the requirements.bzl file rather than make your users
73*60517a1eSAndroid Build Coastguard Workerinstall the WORKSPACE setup to generate it.
74*60517a1eSAndroid Build Coastguard WorkerSee https://github.com/bazelbuild/rules_python/issues/608
75*60517a1eSAndroid Build Coastguard Worker
76*60517a1eSAndroid Build Coastguard WorkerThis is the same workflow as Gazelle, which creates `go_repository` rules with
77*60517a1eSAndroid Build Coastguard Worker[`update-repos`](https://github.com/bazelbuild/bazel-gazelle#update-repos)
78*60517a1eSAndroid Build Coastguard Worker
79*60517a1eSAndroid Build Coastguard WorkerTo do this, use the "write to source file" pattern documented in
80*60517a1eSAndroid Build Coastguard Workerhttps://blog.aspect.dev/bazel-can-write-to-the-source-folder
81*60517a1eSAndroid Build Coastguard Workerto put a copy of the generated requirements.bzl into your project.
82*60517a1eSAndroid Build Coastguard WorkerThen load the requirements.bzl file directly rather than from the generated repository.
83*60517a1eSAndroid Build Coastguard WorkerSee the example in rules_python/examples/pip_parse_vendored.
84*60517a1eSAndroid Build Coastguard Worker
85*60517a1eSAndroid Build Coastguard Worker(per-os-arch-requirements)=
86*60517a1eSAndroid Build Coastguard Worker### Requirements for a specific OS/Architecture
87*60517a1eSAndroid Build Coastguard Worker
88*60517a1eSAndroid Build Coastguard WorkerIn some cases you may need to use different requirements files for different OS, Arch combinations. This is enabled via the `requirements_by_platform` attribute in `pip.parse` extension and the `pip_parse` repository rule. The keys of the dictionary are labels to the file and the values are a list of comma separated target (os, arch) tuples.
89*60517a1eSAndroid Build Coastguard Worker
90*60517a1eSAndroid Build Coastguard WorkerFor example:
91*60517a1eSAndroid Build Coastguard Worker```starlark
92*60517a1eSAndroid Build Coastguard Worker    # ...
93*60517a1eSAndroid Build Coastguard Worker    requirements_by_platform = {
94*60517a1eSAndroid Build Coastguard Worker        "requirements_linux_x86_64.txt": "linux_x86_64",
95*60517a1eSAndroid Build Coastguard Worker        "requirements_osx.txt": "osx_*",
96*60517a1eSAndroid Build Coastguard Worker        "requirements_linux_exotic.txt": "linux_exotic",
97*60517a1eSAndroid Build Coastguard Worker        "requirements_some_platforms.txt": "linux_aarch64,windows_*",
98*60517a1eSAndroid Build Coastguard Worker    },
99*60517a1eSAndroid Build Coastguard Worker    # For the list of standard platforms that the rules_python has toolchains for, default to
100*60517a1eSAndroid Build Coastguard Worker    # the following requirements file.
101*60517a1eSAndroid Build Coastguard Worker    requirements_lock = "requirements_lock.txt",
102*60517a1eSAndroid Build Coastguard Worker```
103*60517a1eSAndroid Build Coastguard Worker
104*60517a1eSAndroid Build Coastguard WorkerIn case of duplicate platforms, `rules_python` will raise an error as there has
105*60517a1eSAndroid Build Coastguard Workerto be unambiguous mapping of the requirement files to the (os, arch) tuples.
106*60517a1eSAndroid Build Coastguard Worker
107*60517a1eSAndroid Build Coastguard WorkerAn alternative way is to use per-OS requirement attributes.
108*60517a1eSAndroid Build Coastguard Worker```starlark
109*60517a1eSAndroid Build Coastguard Worker    # ...
110*60517a1eSAndroid Build Coastguard Worker    requirements_windows = "requirements_windows.txt",
111*60517a1eSAndroid Build Coastguard Worker    requirements_darwin = "requirements_darwin.txt",
112*60517a1eSAndroid Build Coastguard Worker    # For the remaining platforms (which is basically only linux OS), use this file.
113*60517a1eSAndroid Build Coastguard Worker    requirements_lock = "requirements_lock.txt",
114*60517a1eSAndroid Build Coastguard Worker)
115*60517a1eSAndroid Build Coastguard Worker```
116*60517a1eSAndroid Build Coastguard Worker
117*60517a1eSAndroid Build Coastguard Worker### pip rules
118*60517a1eSAndroid Build Coastguard Worker
119*60517a1eSAndroid Build Coastguard WorkerNote that since `pip_parse` and `pip.parse` are executed at evaluation time,
120*60517a1eSAndroid Build Coastguard WorkerBazel has no information about the Python toolchain and cannot enforce that the
121*60517a1eSAndroid Build Coastguard Workerinterpreter used to invoke `pip` matches the interpreter used to run
122*60517a1eSAndroid Build Coastguard Worker`py_binary` targets. By default, `pip_parse` uses the system command
123*60517a1eSAndroid Build Coastguard Worker`"python3"`. To override this, pass in the `python_interpreter` attribute or
124*60517a1eSAndroid Build Coastguard Worker`python_interpreter_target` attribute to `pip_parse`. The `pip.parse` `bzlmod` extension
125*60517a1eSAndroid Build Coastguard Workerby default uses the hermetic python toolchain for the host platform.
126*60517a1eSAndroid Build Coastguard Worker
127*60517a1eSAndroid Build Coastguard WorkerYou can have multiple `pip_parse`s in the same workspace, or use the pip
128*60517a1eSAndroid Build Coastguard Workerextension multiple times when using bzlmod. This configuration will create
129*60517a1eSAndroid Build Coastguard Workermultiple external repos that have no relation to one another and may result in
130*60517a1eSAndroid Build Coastguard Workerdownloading the same wheels numerous times.
131*60517a1eSAndroid Build Coastguard Worker
132*60517a1eSAndroid Build Coastguard WorkerAs with any repository rule, if you would like to ensure that `pip_parse` is
133*60517a1eSAndroid Build Coastguard Workerre-executed to pick up a non-hermetic change to your environment (e.g., updating
134*60517a1eSAndroid Build Coastguard Workeryour system `python` interpreter), you can force it to re-execute by running
135*60517a1eSAndroid Build Coastguard Worker`bazel sync --only [pip_parse name]`.
136*60517a1eSAndroid Build Coastguard Worker
137*60517a1eSAndroid Build Coastguard Worker{#using-third-party-packages}
138*60517a1eSAndroid Build Coastguard Worker## Using third party packages as dependencies
139*60517a1eSAndroid Build Coastguard Worker
140*60517a1eSAndroid Build Coastguard WorkerEach extracted wheel repo contains a `py_library` target representing
141*60517a1eSAndroid Build Coastguard Workerthe wheel's contents. There are two ways to access this library. The
142*60517a1eSAndroid Build Coastguard Workerfirst uses the `requirement()` function defined in the central
143*60517a1eSAndroid Build Coastguard Workerrepo's `//:requirements.bzl` file. This function maps a pip package
144*60517a1eSAndroid Build Coastguard Workername to a label:
145*60517a1eSAndroid Build Coastguard Worker
146*60517a1eSAndroid Build Coastguard Worker```starlark
147*60517a1eSAndroid Build Coastguard Workerload("@my_deps//:requirements.bzl", "requirement")
148*60517a1eSAndroid Build Coastguard Worker
149*60517a1eSAndroid Build Coastguard Workerpy_library(
150*60517a1eSAndroid Build Coastguard Worker    name = "mylib",
151*60517a1eSAndroid Build Coastguard Worker    srcs = ["mylib.py"],
152*60517a1eSAndroid Build Coastguard Worker    deps = [
153*60517a1eSAndroid Build Coastguard Worker        ":myotherlib",
154*60517a1eSAndroid Build Coastguard Worker        requirement("some_pip_dep"),
155*60517a1eSAndroid Build Coastguard Worker        requirement("another_pip_dep"),
156*60517a1eSAndroid Build Coastguard Worker    ]
157*60517a1eSAndroid Build Coastguard Worker)
158*60517a1eSAndroid Build Coastguard Worker```
159*60517a1eSAndroid Build Coastguard Worker
160*60517a1eSAndroid Build Coastguard WorkerThe reason `requirement()` exists is to insulate from
161*60517a1eSAndroid Build Coastguard Workerchanges to the underlying repository and label strings. However, those
162*60517a1eSAndroid Build Coastguard Workerlabels have become directly used, so aren't able to easily change regardless.
163*60517a1eSAndroid Build Coastguard Worker
164*60517a1eSAndroid Build Coastguard WorkerOn the other hand, using `requirement()` has several drawbacks; see
165*60517a1eSAndroid Build Coastguard Worker[this issue][requirements-drawbacks] for an enumeration. If you don't
166*60517a1eSAndroid Build Coastguard Workerwant to use `requirement()`, you can use the library
167*60517a1eSAndroid Build Coastguard Workerlabels directly instead. For `pip_parse`, the labels are of the following form:
168*60517a1eSAndroid Build Coastguard Worker
169*60517a1eSAndroid Build Coastguard Worker```starlark
170*60517a1eSAndroid Build Coastguard Worker@{name}//{package}
171*60517a1eSAndroid Build Coastguard Worker```
172*60517a1eSAndroid Build Coastguard Worker
173*60517a1eSAndroid Build Coastguard WorkerHere `name` is the `name` attribute that was passed to `pip_parse` and
174*60517a1eSAndroid Build Coastguard Worker`package` is the pip package name with characters that are illegal in
175*60517a1eSAndroid Build Coastguard WorkerBazel label names (e.g. `-`, `.`) replaced with `_`. If you need to
176*60517a1eSAndroid Build Coastguard Workerupdate `name` from "old" to "new", then you can run the following
177*60517a1eSAndroid Build Coastguard Workerbuildozer command:
178*60517a1eSAndroid Build Coastguard Worker
179*60517a1eSAndroid Build Coastguard Worker```shell
180*60517a1eSAndroid Build Coastguard Workerbuildozer 'substitute deps @old//([^/]+) @new//${1}' //...:*
181*60517a1eSAndroid Build Coastguard Worker```
182*60517a1eSAndroid Build Coastguard Worker
183*60517a1eSAndroid Build Coastguard Worker[requirements-drawbacks]: https://github.com/bazelbuild/rules_python/issues/414
184*60517a1eSAndroid Build Coastguard Worker
185*60517a1eSAndroid Build Coastguard Worker### Entry points
186*60517a1eSAndroid Build Coastguard Worker
187*60517a1eSAndroid Build Coastguard WorkerIf you would like to access [entry points][whl_ep], see the `py_console_script_binary` rule documentation,
188*60517a1eSAndroid Build Coastguard Workerwhich can help you create a `py_binary` target for a particular console script exposed by a package.
189*60517a1eSAndroid Build Coastguard Worker
190*60517a1eSAndroid Build Coastguard Worker[whl_ep]: https://packaging.python.org/specifications/entry-points/
191*60517a1eSAndroid Build Coastguard Worker
192*60517a1eSAndroid Build Coastguard Worker### 'Extras' dependencies
193*60517a1eSAndroid Build Coastguard Worker
194*60517a1eSAndroid Build Coastguard WorkerAny 'extras' specified in the requirements lock file will be automatically added
195*60517a1eSAndroid Build Coastguard Workeras transitive dependencies of the package. In the example above, you'd just put
196*60517a1eSAndroid Build Coastguard Worker`requirement("useful_dep")` or `@pypi//useful_dep`.
197*60517a1eSAndroid Build Coastguard Worker
198*60517a1eSAndroid Build Coastguard Worker### Consuming Wheel Dists Directly
199*60517a1eSAndroid Build Coastguard Worker
200*60517a1eSAndroid Build Coastguard WorkerIf you need to depend on the wheel dists themselves, for instance, to pass them
201*60517a1eSAndroid Build Coastguard Workerto some other packaging tool, you can get a handle to them with the
202*60517a1eSAndroid Build Coastguard Worker`whl_requirement` macro. For example:
203*60517a1eSAndroid Build Coastguard Worker
204*60517a1eSAndroid Build Coastguard Worker```starlark
205*60517a1eSAndroid Build Coastguard Workerload("@pypi//:requirements.bzl", "whl_requirement")
206*60517a1eSAndroid Build Coastguard Worker
207*60517a1eSAndroid Build Coastguard Workerfilegroup(
208*60517a1eSAndroid Build Coastguard Worker    name = "whl_files",
209*60517a1eSAndroid Build Coastguard Worker    data = [
210*60517a1eSAndroid Build Coastguard Worker        # This is equivalent to "@pypi//boto3:whl"
211*60517a1eSAndroid Build Coastguard Worker        whl_requirement("boto3"),
212*60517a1eSAndroid Build Coastguard Worker    ]
213*60517a1eSAndroid Build Coastguard Worker)
214*60517a1eSAndroid Build Coastguard Worker```
215*60517a1eSAndroid Build Coastguard Worker
216*60517a1eSAndroid Build Coastguard Worker### Creating a filegroup of files within a whl
217*60517a1eSAndroid Build Coastguard Worker
218*60517a1eSAndroid Build Coastguard WorkerThe rule {obj}`whl_filegroup` exists as an easy way to extract the necessary files
219*60517a1eSAndroid Build Coastguard Workerfrom a whl file without the need to modify the `BUILD.bazel` contents of the
220*60517a1eSAndroid Build Coastguard Workerwhl repositories generated via `pip_repository`. Use it similarly to the `filegroup`
221*60517a1eSAndroid Build Coastguard Workerabove. See the API docs for more information.
222*60517a1eSAndroid Build Coastguard Worker
223*60517a1eSAndroid Build Coastguard Worker(advance-topics)=
224*60517a1eSAndroid Build Coastguard Worker## Advanced topics
225*60517a1eSAndroid Build Coastguard Worker
226*60517a1eSAndroid Build Coastguard Worker(circular-deps)=
227*60517a1eSAndroid Build Coastguard Worker### Circular dependencies
228*60517a1eSAndroid Build Coastguard Worker
229*60517a1eSAndroid Build Coastguard WorkerSometimes PyPi packages contain dependency cycles -- for instance a particular
230*60517a1eSAndroid Build Coastguard Workerversion `sphinx` (this is no longer the case in the latest version as of
231*60517a1eSAndroid Build Coastguard Worker2024-06-02) depends on `sphinxcontrib-serializinghtml`. When using them as
232*60517a1eSAndroid Build Coastguard Worker`requirement()`s, ala
233*60517a1eSAndroid Build Coastguard Worker
234*60517a1eSAndroid Build Coastguard Worker```
235*60517a1eSAndroid Build Coastguard Workerpy_binary(
236*60517a1eSAndroid Build Coastguard Worker    name = "doctool",
237*60517a1eSAndroid Build Coastguard Worker    ...
238*60517a1eSAndroid Build Coastguard Worker    deps = [
239*60517a1eSAndroid Build Coastguard Worker        requirement("sphinx"),
240*60517a1eSAndroid Build Coastguard Worker    ],
241*60517a1eSAndroid Build Coastguard Worker)
242*60517a1eSAndroid Build Coastguard Worker```
243*60517a1eSAndroid Build Coastguard Worker
244*60517a1eSAndroid Build Coastguard WorkerBazel will protest because it doesn't support cycles in the build graph --
245*60517a1eSAndroid Build Coastguard Worker
246*60517a1eSAndroid Build Coastguard Worker```
247*60517a1eSAndroid Build Coastguard WorkerERROR: .../external/pypi_sphinxcontrib_serializinghtml/BUILD.bazel:44:6: in alias rule @pypi_sphinxcontrib_serializinghtml//:pkg: cycle in dependency graph:
248*60517a1eSAndroid Build Coastguard Worker    //:doctool (...)
249*60517a1eSAndroid Build Coastguard Worker    @pypi//sphinxcontrib_serializinghtml:pkg (...)
250*60517a1eSAndroid Build Coastguard Worker.-> @pypi_sphinxcontrib_serializinghtml//:pkg (...)
251*60517a1eSAndroid Build Coastguard Worker|   @pypi_sphinxcontrib_serializinghtml//:_pkg (...)
252*60517a1eSAndroid Build Coastguard Worker|   @pypi_sphinx//:pkg (...)
253*60517a1eSAndroid Build Coastguard Worker|   @pypi_sphinx//:_pkg (...)
254*60517a1eSAndroid Build Coastguard Worker`-- @pypi_sphinxcontrib_serializinghtml//:pkg (...)
255*60517a1eSAndroid Build Coastguard Worker```
256*60517a1eSAndroid Build Coastguard Worker
257*60517a1eSAndroid Build Coastguard WorkerThe `experimental_requirement_cycles` argument allows you to work around these
258*60517a1eSAndroid Build Coastguard Workerissues by specifying groups of packages which form cycles. `pip_parse` will
259*60517a1eSAndroid Build Coastguard Workertransparently fix the cycles for you and provide the cyclic dependencies
260*60517a1eSAndroid Build Coastguard Workersimultaneously.
261*60517a1eSAndroid Build Coastguard Worker
262*60517a1eSAndroid Build Coastguard Worker```starlark
263*60517a1eSAndroid Build Coastguard Workerpip_parse(
264*60517a1eSAndroid Build Coastguard Worker    ...
265*60517a1eSAndroid Build Coastguard Worker    experimental_requirement_cycles = {
266*60517a1eSAndroid Build Coastguard Worker        "sphinx": [
267*60517a1eSAndroid Build Coastguard Worker            "sphinx",
268*60517a1eSAndroid Build Coastguard Worker            "sphinxcontrib-serializinghtml",
269*60517a1eSAndroid Build Coastguard Worker        ]
270*60517a1eSAndroid Build Coastguard Worker    },
271*60517a1eSAndroid Build Coastguard Worker)
272*60517a1eSAndroid Build Coastguard Worker```
273*60517a1eSAndroid Build Coastguard Worker
274*60517a1eSAndroid Build Coastguard Worker`pip_parse` supports fixing multiple cycles simultaneously, however cycles must
275*60517a1eSAndroid Build Coastguard Workerbe distinct. `apache-airflow` for instance has dependency cycles with a number
276*60517a1eSAndroid Build Coastguard Workerof its optional dependencies, which means those optional dependencies must all
277*60517a1eSAndroid Build Coastguard Workerbe a part of the `airflow` cycle. For instance --
278*60517a1eSAndroid Build Coastguard Worker
279*60517a1eSAndroid Build Coastguard Worker```starlark
280*60517a1eSAndroid Build Coastguard Workerpip_parse(
281*60517a1eSAndroid Build Coastguard Worker    ...
282*60517a1eSAndroid Build Coastguard Worker    experimental_requirement_cycles = {
283*60517a1eSAndroid Build Coastguard Worker        "airflow": [
284*60517a1eSAndroid Build Coastguard Worker            "apache-airflow",
285*60517a1eSAndroid Build Coastguard Worker            "apache-airflow-providers-common-sql",
286*60517a1eSAndroid Build Coastguard Worker            "apache-airflow-providers-postgres",
287*60517a1eSAndroid Build Coastguard Worker            "apache-airflow-providers-sqlite",
288*60517a1eSAndroid Build Coastguard Worker        ]
289*60517a1eSAndroid Build Coastguard Worker    }
290*60517a1eSAndroid Build Coastguard Worker)
291*60517a1eSAndroid Build Coastguard Worker```
292*60517a1eSAndroid Build Coastguard Worker
293*60517a1eSAndroid Build Coastguard WorkerAlternatively, one could resolve the cycle by removing one leg of it.
294*60517a1eSAndroid Build Coastguard Worker
295*60517a1eSAndroid Build Coastguard WorkerFor example while `apache-airflow-providers-sqlite` is "baked into" the Airflow
296*60517a1eSAndroid Build Coastguard Workerpackage, `apache-airflow-providers-postgres` is not and is an optional feature.
297*60517a1eSAndroid Build Coastguard WorkerRather than listing `apache-airflow[postgres]` in your `requirements.txt` which
298*60517a1eSAndroid Build Coastguard Workerwould expose a cycle via the extra, one could either _manually_ depend on
299*60517a1eSAndroid Build Coastguard Worker`apache-airflow` and `apache-airflow-providers-postgres` separately as
300*60517a1eSAndroid Build Coastguard Workerrequirements. Bazel rules which need only `apache-airflow` can take it as a
301*60517a1eSAndroid Build Coastguard Workerdependency, and rules which explicitly want to mix in
302*60517a1eSAndroid Build Coastguard Worker`apache-airflow-providers-postgres` now can.
303*60517a1eSAndroid Build Coastguard Worker
304*60517a1eSAndroid Build Coastguard WorkerAlternatively, one could use `rules_python`'s patching features to remove one
305*60517a1eSAndroid Build Coastguard Workerleg of the dependency manually. For instance by making
306*60517a1eSAndroid Build Coastguard Worker`apache-airflow-providers-postgres` not explicitly depend on `apache-airflow` or
307*60517a1eSAndroid Build Coastguard Workerperhaps `apache-airflow-providers-common-sql`.
308*60517a1eSAndroid Build Coastguard Worker
309*60517a1eSAndroid Build Coastguard Worker
310*60517a1eSAndroid Build Coastguard Worker(bazel-downloader)=
311*60517a1eSAndroid Build Coastguard Worker### Bazel downloader and multi-platform wheel hub repository.
312*60517a1eSAndroid Build Coastguard Worker
313*60517a1eSAndroid Build Coastguard WorkerThe `bzlmod` `pip.parse` call supports pulling information from `PyPI` (or a
314*60517a1eSAndroid Build Coastguard Workercompatible mirror) and it will ensure that the [bazel
315*60517a1eSAndroid Build Coastguard Workerdownloader][bazel_downloader] is used for downloading the wheels. This allows
316*60517a1eSAndroid Build Coastguard Workerthe users to use the [credential helper](#credential-helper) to authenticate
317*60517a1eSAndroid Build Coastguard Workerwith the mirror and it also ensures that the distribution downloads are cached.
318*60517a1eSAndroid Build Coastguard WorkerIt also avoids using `pip` altogether and results in much faster dependency
319*60517a1eSAndroid Build Coastguard Workerfetching.
320*60517a1eSAndroid Build Coastguard Worker
321*60517a1eSAndroid Build Coastguard WorkerThis can be enabled by `experimental_index_url` and related flags as shown in
322*60517a1eSAndroid Build Coastguard Workerthe {gh-path}`examples/bzlmod/MODULE.bazel` example.
323*60517a1eSAndroid Build Coastguard Worker
324*60517a1eSAndroid Build Coastguard WorkerWhen using this feature during the `pip` extension evaluation you will see the accessed indexes similar to below:
325*60517a1eSAndroid Build Coastguard Worker```console
326*60517a1eSAndroid Build Coastguard WorkerLoading: 0 packages loaded
327*60517a1eSAndroid Build Coastguard Worker    currently loading: docs/
328*60517a1eSAndroid Build Coastguard Worker    Fetching module extension pip in @@//python/extensions:pip.bzl; starting
329*60517a1eSAndroid Build Coastguard Worker    Fetching https://pypi.org/simple/twine/
330*60517a1eSAndroid Build Coastguard Worker```
331*60517a1eSAndroid Build Coastguard Worker
332*60517a1eSAndroid Build Coastguard WorkerThis does not mean that `rules_python` is fetching the wheels eagerly, but it
333*60517a1eSAndroid Build Coastguard Workerrather means that it is calling the PyPI server to get the Simple API response
334*60517a1eSAndroid Build Coastguard Workerto get the list of all available source and wheel distributions. Once it has
335*60517a1eSAndroid Build Coastguard Workergot all of the available distributions, it will select the right ones depending
336*60517a1eSAndroid Build Coastguard Workeron the `sha256` values in your `requirements_lock.txt` file. The compatible
337*60517a1eSAndroid Build Coastguard Workerdistribution URLs will be then written to the `MODULE.bazel.lock` file. Currently
338*60517a1eSAndroid Build Coastguard Workerusers wishing to use the lock file with `rules_python` with this feature have
339*60517a1eSAndroid Build Coastguard Workerto set an environment variable `RULES_PYTHON_OS_ARCH_LOCK_FILE=0` which will
340*60517a1eSAndroid Build Coastguard Workerbecome default in the next release.
341*60517a1eSAndroid Build Coastguard Worker
342*60517a1eSAndroid Build Coastguard WorkerFetching the distribution information from the PyPI allows `rules_python` to
343*60517a1eSAndroid Build Coastguard Workerknow which `whl` should be used on which target platform and it will determine
344*60517a1eSAndroid Build Coastguard Workerthat by parsing the `whl` filename based on [PEP600], [PEP656] standards. This
345*60517a1eSAndroid Build Coastguard Workerallows the user to configure the behaviour by using the following publicly
346*60517a1eSAndroid Build Coastguard Workeravailable flags:
347*60517a1eSAndroid Build Coastguard Worker* {obj}`--@rules_python//python/config_settings:py_linux_libc` for selecting the Linux libc variant.
348*60517a1eSAndroid Build Coastguard Worker* {obj}`--@rules_python//python/config_settings:pip_whl` for selecting `whl` distribution preference.
349*60517a1eSAndroid Build Coastguard Worker* {obj}`--@rules_python//python/config_settings:pip_whl_osx_arch` for selecting MacOS wheel preference.
350*60517a1eSAndroid Build Coastguard Worker* {obj}`--@rules_python//python/config_settings:pip_whl_glibc_version` for selecting the GLIBC version compatibility.
351*60517a1eSAndroid Build Coastguard Worker* {obj}`--@rules_python//python/config_settings:pip_whl_muslc_version` for selecting the musl version compatibility.
352*60517a1eSAndroid Build Coastguard Worker* {obj}`--@rules_python//python/config_settings:pip_whl_osx_version` for selecting MacOS version compatibility.
353*60517a1eSAndroid Build Coastguard Worker
354*60517a1eSAndroid Build Coastguard Worker[bazel_downloader]: https://bazel.build/rules/lib/builtins/repository_ctx#download
355*60517a1eSAndroid Build Coastguard Worker[pep600]: https://peps.python.org/pep-0600/
356*60517a1eSAndroid Build Coastguard Worker[pep656]: https://peps.python.org/pep-0656/
357*60517a1eSAndroid Build Coastguard Worker
358*60517a1eSAndroid Build Coastguard Worker(credential-helper)=
359*60517a1eSAndroid Build Coastguard Worker### Credential Helper
360*60517a1eSAndroid Build Coastguard Worker
361*60517a1eSAndroid Build Coastguard WorkerThe "use Bazel downloader for python wheels" experimental feature includes support for the Bazel
362*60517a1eSAndroid Build Coastguard Worker[Credential Helper][cred-helper-design].
363*60517a1eSAndroid Build Coastguard Worker
364*60517a1eSAndroid Build Coastguard WorkerYour python artifact registry may provide a credential helper for you. Refer to your index's docs
365*60517a1eSAndroid Build Coastguard Workerto see if one is provided.
366*60517a1eSAndroid Build Coastguard Worker
367*60517a1eSAndroid Build Coastguard WorkerSee the [Credential Helper Spec][cred-helper-spec] for details.
368*60517a1eSAndroid Build Coastguard Worker
369*60517a1eSAndroid Build Coastguard Worker[cred-helper-design]: https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md
370*60517a1eSAndroid Build Coastguard Worker[cred-helper-spec]: https://github.com/EngFlow/credential-helper-spec/blob/main/spec.md
371*60517a1eSAndroid Build Coastguard Worker
372*60517a1eSAndroid Build Coastguard Worker
373*60517a1eSAndroid Build Coastguard Worker#### Basic Example:
374*60517a1eSAndroid Build Coastguard Worker
375*60517a1eSAndroid Build Coastguard WorkerThe simplest form of a credential helper is a bash script that accepts an arg and spits out JSON to
376*60517a1eSAndroid Build Coastguard Workerstdout. For a service like Google Artifact Registry that uses ['Basic' HTTP Auth][rfc7617] and does
377*60517a1eSAndroid Build Coastguard Workernot provide a credential helper that conforms to the [spec][cred-helper-spec], the script might
378*60517a1eSAndroid Build Coastguard Workerlook like:
379*60517a1eSAndroid Build Coastguard Worker
380*60517a1eSAndroid Build Coastguard Worker```bash
381*60517a1eSAndroid Build Coastguard Worker#!/bin/bash
382*60517a1eSAndroid Build Coastguard Worker# cred_helper.sh
383*60517a1eSAndroid Build Coastguard WorkerARG=$1  # but we don't do anything with it as it's always "get"
384*60517a1eSAndroid Build Coastguard Worker
385*60517a1eSAndroid Build Coastguard Worker# formatting is optional
386*60517a1eSAndroid Build Coastguard Workerecho '{'
387*60517a1eSAndroid Build Coastguard Workerecho '  "headers": {'
388*60517a1eSAndroid Build Coastguard Workerecho '    "Authorization": ["Basic dGVzdDoxMjPCow=="]'
389*60517a1eSAndroid Build Coastguard Workerecho '  }'
390*60517a1eSAndroid Build Coastguard Workerecho '}'
391*60517a1eSAndroid Build Coastguard Worker```
392*60517a1eSAndroid Build Coastguard Worker
393*60517a1eSAndroid Build Coastguard WorkerConfigure Bazel to use this credential helper for your python index `example.com`:
394*60517a1eSAndroid Build Coastguard Worker
395*60517a1eSAndroid Build Coastguard Worker```
396*60517a1eSAndroid Build Coastguard Worker# .bazelrc
397*60517a1eSAndroid Build Coastguard Workerbuild --credential_helper=example.com=/full/path/to/cred_helper.sh
398*60517a1eSAndroid Build Coastguard Worker```
399*60517a1eSAndroid Build Coastguard Worker
400*60517a1eSAndroid Build Coastguard WorkerBazel will call this file like `cred_helper.sh get` and use the returned JSON to inject headers
401*60517a1eSAndroid Build Coastguard Workerinto whatever HTTP(S) request it performs against `example.com`.
402*60517a1eSAndroid Build Coastguard Worker
403*60517a1eSAndroid Build Coastguard Worker[rfc7617]: https://datatracker.ietf.org/doc/html/rfc7617
404