An aspect to enforce correct dependencies for py_*
targets.
This aspect inspects Python sources to discover imports, and then verifies that imports are either local to the target or come from a declared dependency.
This aspect will run over any py_binary
, py_library
or py_test
target.
Presently, only bzlmod setup is supported.
Add rules_pydeps to your MODULE.bazel:
bazel_dep(name = "rules_pydeps", version = "0.0.0")
Configure the external deps analyzer:
reqs = use_extension("@rules_pydeps//pydeps:reqs.bzl", "reqs")
reqs.requirements(
requirements_in = "//:requirements.in",
pip_requirements = "@pip//:requirements.bzl",
)
use_repo(reqs, "reqs")
Configure deps_enforcer aspect:
Define a new aspect in a .bzl
file (such as ./tools/aspects.bzl
):
load("@rules_pydeps//pydeps:pydeps.bzl", "deps_enforcer_aspect_factory")
deps_enforcer = deps_enforcer_aspect_factory(
pip_deps_index = Label("@reqs//:pip_deps_index"),
)
Update your .bazelrc
to include this new aspect:
# register deps_enforcer aspect with Bazel
build --aspects //tools:aspects.bzl%deps_enforcer
# optionally, default enable enforcement
build --output_groups=+pydeps
Label any target with the tag no-deps-enforcer
, or customize suppression tags:
deps_enforcer = deps_enforcer_aspect_factory(
pip_deps_index = Label("@reqs//:pip_deps_index"),
suppression_tags = ["no-lint"],
)
To make it easier to manage your aspects, it's possible to set an additional OutputGroupInfo name:
deps_enforcer = deps_enforcer_aspect_factory(
pip_deps_index = Label("@reqs//:pip_deps_index"),
output_groups = ["lint"],
)
This may assist in configuring aspects to run together in your .bazelrc.
Some Python libraries dynamically load dependencies based on what's on PYTHONPATH (such as pyxlsb
for pandas
). It may be necessary to import these dependencies, but the deps enforcer will detect these as extra imports.
To overcome this, add a tag to your target of the form 'runtime:requirement("dep")'
or runtime://my/internal:dep
.
As an example:
py_library(
name = "example",
srcs = ["example.py"]
deps = [
requirement("pandas"),
requirement("pyxlsb"),
],
tags = [
'runtime:requirement("pyxlsb")',
],
)
It may be simpler to define a macro to handle this for you.