This course assumes that you selected the “Python” option when you ran aspect init
to create a new repository and also enabled Code Generation, Formatting and Linting, Version Stamping, and OCI Containers.
Requests example code
Add the “getting started” code for the Python “requests” module. It gives a good example of installing an external package from PyPI.
Create a folder named app
, then create a file __main__.py
(double underscores before and after main
). This is the Python convention for an executable entry-point.
Copy the first code block from https://www.w3schools.com/python/module_requests.asp:
import requests
x = requests.get('https://w3schools.com/python/demopage.htm')
print(x.text)
Declare and pin requirements
Since the requests
package is a new dependency of the repository, you first need to declare that. This example uses a pyproject.toml
. Bazel’s rules_python supports the simpler requirements.txt
format as well.
Add the “requests” string to the dependencies
section, which should now look like this:
dependencies = [
"requests",
]
Next you need to “compile” or “pin” the dependencies. Bazel can only provide reproducible builds if you give fully-locked description of the dependencies. There are a few options for pip compile
tools. This exercise uses uv pip compile
which comes from rules_uv, and it provides executable targets to update the pinned dependencies, which you can use with bazel run //requirements:runtime.update
.
Take a look in the requirements
folder. There are files for different purposes; for example test.in
lists the pytest
dependency needed for testing. Since there are multiple pinned dependencies, it would require multiple bazel run
commands to update everything. The repository has a convenience script to make this easy, so you should only need to run:
% ./tools/repin
This results in updates to the requirements/all.in
file, which has the complete, constraint-solved set of dependencies for our repo. It includes hashes of each package for better supply-chain security.
This file is used by rules_python to install dependencies. Note in MODULE.bazel
that it’s referenced by a pip.parse
module extension:
pip.parse(
hub_name = "pip",
python_version = "3.12",
requirements_lock = "//requirements:all.txt",
)
Now you should be ready to use the dependency from Bazel-managed code.
Generate BUILD files
For Bazel to understand the Python code, it expects BUILD
files containing Python rules. Since you’ve written a program, you need to add a py_binary
rule to make it runnable.
As you learned in the Bazel 101 course, you only need to run aspect configure
.
Aspect compiled the Gazelle extension from rules_python, which is much easier than building it yourself. If you don’t use the Aspect CLI, see the 203 course for a guide to installing Gazelle.
Now look in app/BUILD.bazel
to see the generated content.
At this point the py_binary
should be functional, so you can run it with the following command:
% bazel run app:app_bin