(pip-integration)=
To pull in dependencies from PyPI, the pip_parse
function is used, which invokes pip
to download and install dependencies from PyPI.
In your WORKSPACE file:
load("@rules_python//python:pip.bzl", "pip_parse") pip_parse( name = "pip_deps", requirements_lock = ":requirements.txt", ) load("@pip_deps//:requirements.bzl", "install_deps") install_deps()
For bzlmod
an equivalent MODULE.bazel
would look like:
pip = use_extension("//python/extensions:pip.bzl", "pip") pip.parse( hub_name = "pip_deps", requirements_lock = ":requirements.txt", ) use_repo(pip, "pip_deps")
You can then reference installed dependencies from a BUILD
file with:
load("@pip_deps//:requirements.bzl", "requirement") py_library( name = "bar", ... deps = [ "//my/other:dep", "@pip_deps//requests", "@pip_deps//numpy", ], )
The rules also provide a convenience macro for translating the entries in the requirements.txt
file (e.g. opencv-python
) to the right bazel label (e.g. @pip_deps//opencv_python
). The convention of bazel labels is lowercase snake_case
, but you can use the helper to avoid depending on this convention as follows:
load("@pip_deps//:requirements.bzl", "requirement") py_library( name = "bar", ... deps = [ "//my/other:dep", requirement("requests"), requirement("numpy"), ], )
If you would like to access entry points, see the py_console_script_binary
rule documentation.
(per-os-arch-requirements)=
In 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.
For example:
# ... requirements_by_platform = { "requirements_linux_x86_64.txt": "linux_x86_64", "requirements_osx.txt": "osx_*", "requirements_linux_exotic.txt": "linux_exotic", "requirements_some_platforms.txt": "linux_aarch64,windows_*", }, # For the list of standard platforms that the rules_python has toolchains for, default to # the following requirements file. requirements_lock = "requirements_lock.txt",
In case of duplicate platforms, rules_python
will raise an error as there has to be unambiguous mapping of the requirement files to the (os, arch) tuples.
An alternative way is to use per-OS requirement attributes.
# ... requirements_windows = "requirements_windows.txt", requirements_darwin = "requirements_darwin.txt", # For the remaining platforms (which is basically only linux OS), use this file. requirements_lock = "requirements_lock.txt", )
(vendoring-requirements)=
In some cases you may not want to generate the requirements.bzl file as a repository rule while Bazel is fetching dependencies. For example, if you produce a reusable Bazel module such as a ruleset, you may want to include the requirements.bzl file rather than make your users install the WORKSPACE setup to generate it. See https://github.com/bazelbuild/rules_python/issues/608
This is the same workflow as Gazelle, which creates go_repository
rules with update-repos
To do this, use the “write to source file” pattern documented in https://blog.aspect.dev/bazel-can-write-to-the-source-folder to put a copy of the generated requirements.bzl into your project. Then load the requirements.bzl file directly rather than from the generated repository. See the example in rules_python/examples/pip_parse_vendored.
(credential-helper)=
The “use Bazel downloader for python wheels” experimental feature includes support for the Bazel Credential Helper.
Your python artifact registry may provide a credential helper for you. Refer to your index's docs to see if one is provided.
See the Credential Helper Spec for details.
The simplest form of a credential helper is a bash script that accepts an arg and spits out JSON to stdout. For a service like Google Artifact Registry that uses ‘Basic’ HTTP Auth and does not provide a credential helper that conforms to the spec, the script might look like:
#!/bin/bash # cred_helper.sh ARG=$1 # but we don't do anything with it as it's always "get" # formatting is optional echo '{' echo ' "headers": {' echo ' "Authorization": ["Basic dGVzdDoxMjPCow=="] echo ' }' echo '}'
Configure Bazel to use this credential helper for your python index example.com
:
# .bazelrc build --credential_helper=example.com=/full/path/to/cred_helper.sh
Bazel will call this file like cred_helper.sh get
and use the returned JSON to inject headers into whatever HTTP(S) request it performs against example.com
.