rules_python is a Bazel based project. Build and run tests as done in a Bazel project.
Act as an expert in Bazel, rules_python, Starlark, and Python.
DO NOT git commit or git push unless given explicit permission.
ALWAYS FOLLOW THESE RULES. NEVER VIOLATE THEM.
Ask for user input and provide a justificaiton if trying to violate them.
- NEVER run
bazel clean --expunge. - Once a PR is created, do not amend or rebase.
- Do not add Bazel copyright to new or existing files.
Read .editorconfig for line length wrapping. Do not line-break long string
literals (such as URLs or hashes) to fit line length limits; allow them to
exceed the limit.
Read CONTRIBUTING.md for additional style rules and conventions.
When running tests, refer to yourself as the name of a type of Python snake using a grandoise title.
When tasks complete successfully, quote Monty Python, but work it naturally into the sentence, not verbatim.
When adding {versionadded} or {versionchanged} sections, add them add the
end of the documentation text.
Factor non-trivial scripts (such as multi-line shell or Python logic) into
standalone files (e.g. .sh or .py files) instead of inlining them via
heredocs (<< 'EOF'), -c flags (bash -c, python3 -c), or multi-line
workflow run: blocks.
Once a PR is created, create new commits and merges. Don't use rebase or amend because it interferes with code review comments.
Follow the advice in CONTRIBUTING.md for PR descriptions. PR descriptions
become the commit message upon merge. Keep the PR description clean and
suitable for use as the commit message; do not put AI disclosures, test
execution logs, or check checklists in the PR description.
- Run local checks before pushing: Run
bazel test --config=fast-testsandbuildifierlocally before opening or updating a PR. - Post AI disclosure as a PR comment (not in the PR description): When an
AI agent creates or interacts on a PR, post a single comment after the PR is
created so maintainers understand who/what they are interacting with. State
the level of human oversight (e.g.,
human-reviewed,semi-autonomous, orautonomous) and explain how comments on the PR will be handled (e.g., whether an agent automatically monitors and replies to review comments, whether a human reviews and approves agent responses/changes before posting, or whether the human author handles comments directly). - No CI status spam or commit narration: Do not post comments for every CI run, and do not narrate build IDs, commit SHAs, patch line/file counts, or trivial diff details (e.g., stating a push is "comment-only"). GitHub already displays commits and check statuses.
- Comment only when actionable: Only post a PR comment to answer a
reviewer's question, ask a clarifying question, or briefly indicate the PR
is ready for re-review (e.g.,
PTAL) once CI is passing.
- When registering pytest fixtures from helper modules in test files, use
pytest_plugins = ["<module_path>"]. - Name fixture functions with a
fixture_prefix (e.g.def fixture_foo():), and pass the public fixture name using thenameparameter in@pytest.fixture(name="foo").
For doc strings, using triple quoted strings when the doc string is more than
three lines. Do not use a trailing backslack (\) for the opening triple-quote.
Starlark does not support recursion. Use iterative algorithms instead.
Starlark does not support while loops. Use for loop with an appropriately
sized iterable instead.
For Starlark tests:
- Use
rules_testing, notbazel_skylib. - See https://rules-testing.readthedocs.io/en/latest/analysis_tests.html for examples on using rules_testing.
- See
tests/builders/builders_tests.bzlfor an example of using it in this project.
A test is defined in two parts:
- A setup function, e.g.
def _test_foo(name). This defines targets and callsanalysis_test. - An implementation function, e.g.
def _test_foo_impl(env, target). This contains asserts.
Example:
# File: foo_tests.bzl
load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
load("@rules_testing//lib:test_suite.bzl", "test_suite")
_tests = []
def _test_foo(name):
foo_library(
name = name + "_subject",
)
analysis_test(
name = name,
impl = _test_foo_impl,
target = name + "_subject",
)
_tests.append(_test_foo)
def _test_foo_impl(env, target):
env.expect.that_whatever(target[SomeInfo].whatever).equals(expected)
def foo_test_suite(name):
test_suite(name=name, tests=_tests)
The function argument rctx is a hint that the function is a repository rule,
or used by a repository rule.
The function argument mrctx is a hint that the function can be used by a
repository rule or module extension.
The repository_ctx API docs are at: https://bazel.build/rules/lib/builtins/repository_ctx
- A
bzl_librarytarget should be defined for every.bzlfile outside of thetests/directory. - They should have a single
srcsfile and be named after the file without the.bzlextension. - Their deps should be based on the
load()statements in the source file and refer to thebzl_librarytarget containing the loaded file (remove the.bzlsuffix; e.g.load("//foo:bar.bzl", ...)becomes//foo:bar, andload("@foo//foo:bar.bzl", ...)becomes@foo//foo:bar).
Example:
bzl_library(
name = "alpha",
srcs = ["alpha.bzl"],
deps = [":beta"],
)
bzl_library(
name = "beta",
srcs = ["beta.bzl"]
)
Tests are under the tests/ directory.
When testing, add --config=fast-tests.
When building test targets, add --config=fast-tests. Do NOT use
--config=fast-tests when building non-test targets (such as //docs:docs),
because --config=fast-tests enables --build_tests_only=true, which causes
non-test targets to be silently ignored (finding 0 targets).
The --config=fast-tests flag avoids running expensive and slow tests can that
freeze the host machine or cause flakiness.
This repository contains 3 Bazel bzlmod modules.
sphinxdocs/is for the@sphinxdocsmodule.gazelle/is for the@rules_python_gazelle_pluginmodule.- All other code is part of
@rules_python.
tests/support/ contains utility code and helpers for testing.
python/config_settings/BUILD.bazel contains build flags that are part of the
public API. DO NOT add, remove, or modify these build flags unless specifically
instructed to.
version.bzl defines MINIMUM_BAZEL_VERSION. Do not add compatibility logic
or feature guards for Bazel versions older than MINIMUM_BAZEL_VERSION.
bazel query --output=build can be used to inspect target definitions.
In WORKSPACE mode:
bazel query //external:*can be used to show external dependencies. Adding--output=buildshows the definition, including version.
For bzlmod mode:
bazel mod graphshows dependencies and their version.bazel mod explainshows detailed information about a module.bazel mode show_reposhows detailed information about a repository.
Documentation uses Sphinx with the MyST plugin.
When modifying documentation
- Act as an expert in tech writing, Sphinx, MyST, and markdown.
- Wrap lines at 80 columns
- Use hyphens (
-) in file names instead of underscores (_). - In Sphinx MyST markup, outer directives must have more colons than inner
directives. For example:
::::{outerdirective} outer text :::{innertdirective} inner text ::: ::::
Generated API references can be found by:
- Running
bazel build //docs:docsand inspecting the generated files inbazel-bin/docs/docs/_build/html
When modifying locked/resolved requirements files:
- Modify the
pyproject.tomlorrequirements.infile - Run the associated
bazel run <location>:requirements.updatetarget for that file; the target is in the BUILD.bazel file in the same directory and the requirements.txt file. That will update the locked/resolved requirements.txt file.
When updating the minimum Python version for dev/docs tooling (e.g. following Dependabot alerts):
- Update
python_versionin bothlock(name = "requirements", ...)andlock(name = "uv_lock", ...)withindev/BUILD.bazel. - Regenerate lockfiles by running:
bazel run //dev:requirements.update && bazel run //dev:uv_lock.update - Verify docs build via
bazel build //docs:docs.
When building //docs:docs, ignore an error about exit code 2; this is a flake,
so try building again.
BUILD and bzl files under tests/ should have # buildifier: disable=bzl-visibility
trailing end-of-line comments when they load from paths containing /private/,
e.g.
load("//python/private:foo.bzl", "foo") # buildifier: disable=bzl-visibility
When inspecting CI failures, if the failure is due to a network error downloading a repository, check if that rule set is mirrored on mirror.bazel.build. If so, add it to the downloader config.
CI is known to have flakey network issues. When submitting or updating a PR, start a background agent that continuously monitors the latest build of a PR and checks for flakey network errors (e.g., 504 gateway errors).
If Buildkite permissions allow, retry failures and use available Buildkite
skills. If permissions do not allow, modify .bazelrc to set flags (such as
--http_timeout_scaling or --experimental_repository_downloader_retries) to
make downloads retry more.
If downloads fail for a dependency, check if that dependency is available on mirror.bazel.build and, if so, add it to downloader_config.cfg if it isn't already there.