...main`.
-#### Steps
-1. Determine what will be the next release, following semver.
-1. Create a tag and push, e.g. `git tag 0.5.0 upstream/main && git push upstream --tags`
-1. Watch the release automation run on https://github.com/bazelbuild/rules_python/actions
-
#### After release creation in Github
1. Ping @philwo to get the new release added to mirror.bazel.build. See [this comment on issue #400](https://github.com/bazelbuild/rules_python/issues/400#issuecomment-779159530) for more context.
diff --git a/MODULE.bazel b/MODULE.bazel
index 92da4020b9..ddd946c78a 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -11,7 +11,7 @@ bazel_dep(name = "bazel_skylib", version = "1.3.0")
bazel_dep(name = "rules_proto", version = "5.3.0-21.7")
bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf")
-internal_deps = use_extension("@rules_python//python:extensions.bzl", "internal_deps")
+internal_deps = use_extension("@rules_python//python/extensions/private:internal_deps.bzl", "internal_deps")
internal_deps.install()
use_repo(
internal_deps,
@@ -46,3 +46,6 @@ use_repo(
"pypi__coverage_cp39_x86_64-apple-darwin",
"pypi__coverage_cp39_x86_64-unknown-linux-gnu",
)
+
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+use_repo(python, "pythons_hub")
diff --git a/README.md b/README.md
index 089837de7d..a3f18869e6 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,13 @@ Bazel team, provides support for the code. However, this repository is part of
the test suite used to vet new Bazel releases. See the [How to
contribute](CONTRIBUTING.md) page for information on our development workflow.
+## `bzlmod` support
+
+- Status: Beta
+- Full Feature Parity: No
+
+See [Bzlmod support](BZLMOD_SUPPORT.md) for more details.
+
## Getting started
The next two sections cover using `rules_python` with bzlmod and
@@ -39,12 +46,12 @@ the older way of configuring bazel with a `WORKSPACE` file.
### Using bzlmod
To import rules_python in your project, you first need to add it to your
-`MODULES.bazel` file, using the snippet provided in the
+`MODULE.bazel` file, using the snippet provided in the
[release you choose](https://github.com/bazelbuild/rules_python/releases).
#### Toolchain registration with bzlmod
-To register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `MODULES.bazel` file:
+To register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `MODULE.bazel` file:
```python
# Find the latest version number here: https://github.com/bazelbuild/rules_python/releases
@@ -161,7 +168,7 @@ target in the appropriate wheel repo.
#### Using bzlmod
-To add pip dependencies to your `MODULES.bazel` file, use the `pip.parse` extension, and call it to create the
+To add pip dependencies to your `MODULE.bazel` file, use the `pip.parse` extension, and call it to create the
central external repo and individual wheel external repos.
```python
diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel
index e1163d9d0e..938ba85dd5 100644
--- a/docs/BUILD.bazel
+++ b/docs/BUILD.bazel
@@ -32,17 +32,6 @@ _DOCS = {
# because they're only used for doc generation. This way, we avoid requiring
# our users to depend on Skylib.
-# Requires Bazel 0.29 onward for public visibility of these .bzl files.
-bzl_library(
- name = "bazel_python_tools",
- srcs = [
- "@bazel_tools//tools/python:private/defs.bzl",
- "@bazel_tools//tools/python:srcs_version.bzl",
- "@bazel_tools//tools/python:toolchain.bzl",
- "@bazel_tools//tools/python:utils.bzl",
- ],
-)
-
bzl_library(
name = "bazel_repo_tools",
srcs = [
@@ -57,7 +46,7 @@ bzl_library(
"//python/private:reexports.bzl",
],
deps = [
- ":bazel_python_tools",
+ ":bazel_repo_tools",
"//python:defs_bzl",
"//python/private:reexports_bzl",
],
@@ -91,6 +80,9 @@ bzl_library(
"//python/private:stamp.bzl",
"//python/private:util.bzl",
],
+ deps = [
+ "//python/private:util_bzl",
+ ],
)
# TODO: Stardoc does not guarantee consistent outputs accross platforms (Unix/Windows).
diff --git a/docs/pip_repository.md b/docs/pip_repository.md
index c02058e08d..7d539c9c44 100644
--- a/docs/pip_repository.md
+++ b/docs/pip_repository.md
@@ -66,10 +66,10 @@ py_binary(
| environment | Environment variables to set in the pip subprocess. Can be used to set common variables such as http_proxy
, https_proxy
and no_proxy
Note that pip is run with "--isolated" on the CLI so PIP_<VAR>_<NAME>
style env vars are ignored, but env vars that control requests and urllib3 can be passed. | Dictionary: String -> String | optional | {}
|
| extra_pip_args | Extra arguments to pass on to pip. Must not contain spaces. | List of strings | optional | []
|
| incompatible_generate_aliases | Allow generating aliases '@pip//<pkg>' -> '@pip_<pkg>//:pkg'. | Boolean | optional | False
|
-| isolated | Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to the underlying pip command. Alternatively, the RULES_PYTHON_PIP_ISOLATED
enviornment varaible can be used to control this flag. | Boolean | optional | True
|
+| isolated | Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to the underlying pip command. Alternatively, the RULES_PYTHON_PIP_ISOLATED
environment variable can be used to control this flag. | Boolean | optional | True
|
| pip_data_exclude | Additional data exclusion parameters to add to the pip packages BUILD file. | List of strings | optional | []
|
| python_interpreter | The python interpreter to use. This can either be an absolute path or the name of a binary found on the host's PATH
environment variable. If no value is set python3
is defaulted for Unix systems and python.exe
for Windows. | String | optional | ""
|
-| python_interpreter_target | If you are using a custom python interpreter built by another repository rule, use this attribute to specify its BUILD target. This allows pip_repository to invoke pip using the same interpreter as your toolchain. If set, takes precedence over python_interpreter. | Label | optional | None
|
+| python_interpreter_target | If you are using a custom python interpreter built by another repository rule, use this attribute to specify its BUILD target. This allows pip_repository to invoke pip using the same interpreter as your toolchain. If set, takes precedence over python_interpreter. An example value: "@python3_x86_64-unknown-linux-gnu//:python". | Label | optional | None
|
| quiet | If True, suppress printing stdout and stderr output to the terminal. | Boolean | optional | True
|
| repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<p>For example, an entry "@foo": "@bar"
declares that, for any time this repository depends on @foo
(such as a dependency on @foo//some:target
, it should actually resolve that dependency within globally-declared @bar
(@bar//some:target
). | Dictionary: String -> String | required | |
| repo_prefix | Prefix for the generated packages will be of the form @<prefix><sanitized-package-name>//...
| String | optional | ""
|
@@ -85,8 +85,9 @@ py_binary(
## pip_repository_bzlmod
-pip_repository_bzlmod(name, incompatible_generate_aliases, repo_mapping, requirements_darwin,
- requirements_linux, requirements_lock, requirements_windows)
+pip_repository_bzlmod(name, incompatible_generate_aliases, repo_mapping, repo_name,
+ requirements_darwin, requirements_linux, requirements_lock,
+ requirements_windows)
A rule for bzlmod pip_repository creation. Intended for private use only.
@@ -99,6 +100,7 @@ A rule for bzlmod pip_repository creation. Intended for private use only.
| name | A unique name for this repository. | Name | required | |
| incompatible_generate_aliases | Allow generating aliases in '@pip//:<pkg>' -> '@pip_<pkg>//:pkg'. This replaces the aliases generated by the bzlmod
tooling. | Boolean | optional | False
|
| repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<p>For example, an entry "@foo": "@bar"
declares that, for any time this repository depends on @foo
(such as a dependency on @foo//some:target
, it should actually resolve that dependency within globally-declared @bar
(@bar//some:target
). | Dictionary: String -> String | required | |
+| repo_name | The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name | String | required | |
| requirements_darwin | Override the requirements_lock attribute when the host platform is Mac OS | Label | optional | None
|
| requirements_linux | Override the requirements_lock attribute when the host platform is Linux | Label | optional | None
|
| requirements_lock | A fully resolved 'requirements.txt' pip requirement file containing the transitive set of your dependencies. If this file is passed instead of 'requirements' no resolve will take place and pip_repository will create individual repositories for each of your dependencies so that wheels are fetched/built only for the targets specified by 'build/run/test'. | Label | optional | None
|
@@ -130,10 +132,10 @@ Instantiated from pip_repository and inherits config options from there.
| enable_implicit_namespace_pkgs | If true, disables conversion of native namespace packages into pkg-util style namespace packages. When set all py_binary and py_test targets must specify either legacy_create_init=False
or the global Bazel option --incompatible_default_to_explicit_init_py
to prevent __init__.py
being automatically generated in every directory.
This option is required to support some packages which cannot handle the conversion to pkg-util style. | Boolean | optional | False
|
| environment | Environment variables to set in the pip subprocess. Can be used to set common variables such as http_proxy
, https_proxy
and no_proxy
Note that pip is run with "--isolated" on the CLI so PIP_<VAR>_<NAME>
style env vars are ignored, but env vars that control requests and urllib3 can be passed. | Dictionary: String -> String | optional | {}
|
| extra_pip_args | Extra arguments to pass on to pip. Must not contain spaces. | List of strings | optional | []
|
-| isolated | Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to the underlying pip command. Alternatively, the RULES_PYTHON_PIP_ISOLATED
enviornment varaible can be used to control this flag. | Boolean | optional | True
|
+| isolated | Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to the underlying pip command. Alternatively, the RULES_PYTHON_PIP_ISOLATED
environment variable can be used to control this flag. | Boolean | optional | True
|
| pip_data_exclude | Additional data exclusion parameters to add to the pip packages BUILD file. | List of strings | optional | []
|
| python_interpreter | The python interpreter to use. This can either be an absolute path or the name of a binary found on the host's PATH
environment variable. If no value is set python3
is defaulted for Unix systems and python.exe
for Windows. | String | optional | ""
|
-| python_interpreter_target | If you are using a custom python interpreter built by another repository rule, use this attribute to specify its BUILD target. This allows pip_repository to invoke pip using the same interpreter as your toolchain. If set, takes precedence over python_interpreter. | Label | optional | None
|
+| python_interpreter_target | If you are using a custom python interpreter built by another repository rule, use this attribute to specify its BUILD target. This allows pip_repository to invoke pip using the same interpreter as your toolchain. If set, takes precedence over python_interpreter. An example value: "@python3_x86_64-unknown-linux-gnu//:python". | Label | optional | None
|
| quiet | If True, suppress printing stdout and stderr output to the terminal. | Boolean | optional | True
|
| repo | Pointer to parent repo name. Used to make these rules rerun if the parent repo changes. | String | required | |
| repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<p>For example, an entry "@foo": "@bar"
declares that, for any time this repository depends on @foo
(such as a dependency on @foo//some:target
, it should actually resolve that dependency within globally-declared @bar
(@bar//some:target
). | Dictionary: String -> String | required | |
diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel
index 3ef89054c9..feb1cfbd4e 100644
--- a/examples/BUILD.bazel
+++ b/examples/BUILD.bazel
@@ -22,6 +22,11 @@ bazel_integration_test(
timeout = "long",
)
+bazel_integration_test(
+ name = "bzlmod_build_file_generation_example",
+ timeout = "long",
+)
+
bazel_integration_test(
name = "pip_install_example",
timeout = "long",
diff --git a/examples/build_file_generation/.bazelrc b/examples/build_file_generation/.bazelrc
index f23315a7a1..28f634bef6 100644
--- a/examples/build_file_generation/.bazelrc
+++ b/examples/build_file_generation/.bazelrc
@@ -1,4 +1,4 @@
-test --test_output=errors
+test --test_output=errors --enable_runfiles
# Windows requires these for multi-python support:
build --enable_runfiles
diff --git a/examples/build_file_generation/MODULE.bazel b/examples/build_file_generation/MODULE.bazel
deleted file mode 100644
index 5f79fec486..0000000000
--- a/examples/build_file_generation/MODULE.bazel
+++ /dev/null
@@ -1,43 +0,0 @@
-module(
- name = "example_bzlmod",
- version = "0.0.0",
- compatibility_level = 1,
-)
-
-bazel_dep(name = "rules_python", version = "0.19.0")
-bazel_dep(name = "rules_python_gazelle_plugin", version = "0.19.0")
-bazel_dep(name = "gazelle", version = "0.29.0", repo_name = "bazel_gazelle")
-
-# local overrides for the packages for CI purposes.
-# for usual setups you should remove this block.
-local_path_override(
- module_name = "rules_python",
- path = "../..",
-)
-
-local_path_override(
- module_name = "rules_python_gazelle_plugin",
- path = "../../gazelle",
-)
-
-# Register python toolchain
-python = use_extension("@rules_python//python:extensions.bzl", "python")
-python.toolchain(
- name = "python3_9",
- python_version = "3.9",
-)
-use_repo(python, "python3_9_toolchains")
-
-register_toolchains(
- "@python3_9_toolchains//:all",
-)
-
-pip = use_extension("@rules_python//python:extensions.bzl", "pip")
-pip.parse(
- name = "pip",
- # Generate user friendly alias labels for each dependency that we have.
- incompatible_generate_aliases = True,
- requirements_lock = "//:requirements_lock.txt",
- requirements_windows = "//:requirements_windows.txt",
-)
-use_repo(pip, "pip")
diff --git a/examples/build_file_generation/README.md b/examples/build_file_generation/README.md
index 9b2fe1a7be..cd3cd1f109 100644
--- a/examples/build_file_generation/README.md
+++ b/examples/build_file_generation/README.md
@@ -5,7 +5,9 @@ extension, so that targets like `py_library` and `py_binary` can be
automatically created just by running
```sh
-$ bazel run //:gazelle
+bazel run //:requirements.update
+bazel run //:gazelle_python_manifest.update
+bazel run //:gazelle
```
As a demo, try creating a `__main__.py` file in this directory, then
diff --git a/examples/build_file_generation/WORKSPACE.bzlmod b/examples/build_file_generation/WORKSPACE.bzlmod
deleted file mode 100644
index 721e065154..0000000000
--- a/examples/build_file_generation/WORKSPACE.bzlmod
+++ /dev/null
@@ -1,2 +0,0 @@
-# This file will be used when bzlmod is enabled, keep it empty
-# to ensure that all of the setup is done in MODULE.bazel
diff --git a/examples/build_file_generation/gazelle_python.yaml b/examples/build_file_generation/gazelle_python.yaml
index b57e9f02bc..1000757ea5 100644
--- a/examples/build_file_generation/gazelle_python.yaml
+++ b/examples/build_file_generation/gazelle_python.yaml
@@ -115,4 +115,4 @@ manifest:
pip_repository:
name: pip
use_pip_repository_aliases: true
-integrity: 85f073e37e31339508aaaf5e0d5472adae5148fd5f054e9cc586343c026660e1
+integrity: 030d6d99b56c32d6577e616b617260d0a93588af791269162e43391a5a4fa576
diff --git a/examples/build_file_generation/requirements_lock.txt b/examples/build_file_generation/requirements_lock.txt
index f73827a36e..443db71ddc 100644
--- a/examples/build_file_generation/requirements_lock.txt
+++ b/examples/build_file_generation/requirements_lock.txt
@@ -11,7 +11,7 @@ click==8.1.3 \
flask==2.2.2 \
--hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
--hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
- # via -r ./requirements.in
+ # via -r requirements.in
importlib-metadata==5.2.0 \
--hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
--hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
diff --git a/examples/build_file_generation/requirements_windows.txt b/examples/build_file_generation/requirements_windows.txt
index fc097141c5..bdd536fdcf 100644
--- a/examples/build_file_generation/requirements_windows.txt
+++ b/examples/build_file_generation/requirements_windows.txt
@@ -15,7 +15,7 @@ colorama==0.4.6 \
flask==2.2.2 \
--hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
--hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
- # via -r ./requirements.in
+ # via -r requirements.in
importlib-metadata==5.2.0 \
--hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
--hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
diff --git a/examples/bzlmod/BUILD.bazel b/examples/bzlmod/BUILD.bazel
index 7ecc035853..e1f5790631 100644
--- a/examples/bzlmod/BUILD.bazel
+++ b/examples/bzlmod/BUILD.bazel
@@ -1,4 +1,5 @@
-load("@pip//:requirements.bzl", "requirement")
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+load("@pip//:requirements.bzl", "all_requirements", "all_whl_requirements", "requirement")
load("@python3_9//:defs.bzl", py_test_with_transition = "py_test")
load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
@@ -34,6 +35,7 @@ py_binary(
py_test(
name = "test",
srcs = ["test.py"],
+ main = "test.py",
deps = [":lib"],
)
@@ -43,3 +45,13 @@ py_test_with_transition(
main = "test.py",
deps = [":lib"],
)
+
+build_test(
+ name = "all_wheels",
+ targets = all_whl_requirements,
+)
+
+build_test(
+ name = "all_requirements",
+ targets = all_requirements,
+)
diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel
index ce9122810c..145cebd276 100644
--- a/examples/bzlmod/MODULE.bazel
+++ b/examples/bzlmod/MODULE.bazel
@@ -4,13 +4,14 @@ module(
compatibility_level = 1,
)
+bazel_dep(name = "bazel_skylib", version = "1.4.1")
bazel_dep(name = "rules_python", version = "0.0.0")
local_path_override(
module_name = "rules_python",
path = "../..",
)
-python = use_extension("@rules_python//python:extensions.bzl", "python")
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
name = "python3_9",
configure_coverage_tool = True,
@@ -23,9 +24,19 @@ register_toolchains(
"@python3_9_toolchains//:all",
)
-pip = use_extension("@rules_python//python:extensions.bzl", "pip")
+interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter")
+interpreter.install(
+ name = "interpreter_python3_9",
+ python_name = "python3_9",
+)
+use_repo(interpreter, "interpreter_python3_9")
+
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
name = "pip",
+ # Intentionally set it false because the "true" case is already covered by examples/bzlmod_build_file_generation
+ incompatible_generate_aliases = False,
+ python_interpreter_target = "@interpreter_python3_9//:python",
requirements_lock = "//:requirements_lock.txt",
requirements_windows = "//:requirements_windows.txt",
)
diff --git a/examples/bzlmod/entry_point/BUILD.bazel b/examples/bzlmod/entry_point/BUILD.bazel
new file mode 100644
index 0000000000..dfc02b00a0
--- /dev/null
+++ b/examples/bzlmod/entry_point/BUILD.bazel
@@ -0,0 +1,20 @@
+load("@pip//:requirements.bzl", "entry_point")
+load("@rules_python//python:defs.bzl", "py_test")
+
+alias(
+ name = "yamllint",
+ actual = entry_point("yamllint"),
+)
+
+py_test(
+ name = "entry_point_test",
+ srcs = ["test_entry_point.py"],
+ data = [
+ ":yamllint",
+ ],
+ env = {
+ "YAMLLINT_ENTRY_POINT": "$(rlocationpath :yamllint)",
+ },
+ main = "test_entry_point.py",
+ deps = ["@rules_python//python/runfiles"],
+)
diff --git a/examples/bzlmod/entry_point/test_entry_point.py b/examples/bzlmod/entry_point/test_entry_point.py
new file mode 100644
index 0000000000..5a37458348
--- /dev/null
+++ b/examples/bzlmod/entry_point/test_entry_point.py
@@ -0,0 +1,43 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import pathlib
+import subprocess
+import unittest
+
+from python.runfiles import runfiles
+
+
+class ExampleTest(unittest.TestCase):
+ def test_entry_point(self):
+ rlocation_path = os.environ.get("YAMLLINT_ENTRY_POINT")
+ assert (
+ rlocation_path is not None
+ ), "expected 'YAMLLINT_ENTRY_POINT' env variable to be set to rlocation of the tool"
+
+ entry_point = pathlib.Path(runfiles.Create().Rlocation(rlocation_path))
+ self.assertTrue(entry_point.exists(), f"'{entry_point}' does not exist")
+
+ proc = subprocess.run(
+ [str(entry_point), "--version"],
+ check=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ self.assertEqual(proc.stdout.decode("utf-8").strip(), "yamllint 1.28.0")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/examples/bzlmod/gazelle_python.yaml b/examples/bzlmod/gazelle_python.yaml
new file mode 100644
index 0000000000..12096e5837
--- /dev/null
+++ b/examples/bzlmod/gazelle_python.yaml
@@ -0,0 +1,590 @@
+# GENERATED FILE - DO NOT EDIT!
+#
+# To update this file, run:
+# bazel run //:gazelle_python_manifest.update
+
+manifest:
+ modules_mapping:
+ S3: s3cmd
+ S3.ACL: s3cmd
+ S3.AccessLog: s3cmd
+ S3.BidirMap: s3cmd
+ S3.CloudFront: s3cmd
+ S3.Config: s3cmd
+ S3.ConnMan: s3cmd
+ S3.Crypto: s3cmd
+ S3.Custom_httplib27: s3cmd
+ S3.Custom_httplib3x: s3cmd
+ S3.Exceptions: s3cmd
+ S3.ExitCodes: s3cmd
+ S3.FileDict: s3cmd
+ S3.FileLists: s3cmd
+ S3.HashCache: s3cmd
+ S3.MultiPart: s3cmd
+ S3.PkgInfo: s3cmd
+ S3.Progress: s3cmd
+ S3.S3: s3cmd
+ S3.S3Uri: s3cmd
+ S3.SortedDict: s3cmd
+ S3.Utils: s3cmd
+ astroid: astroid
+ astroid.arguments: astroid
+ astroid.astroid_manager: astroid
+ astroid.bases: astroid
+ astroid.brain: astroid
+ astroid.brain.brain_argparse: astroid
+ astroid.brain.brain_attrs: astroid
+ astroid.brain.brain_boto3: astroid
+ astroid.brain.brain_builtin_inference: astroid
+ astroid.brain.brain_collections: astroid
+ astroid.brain.brain_crypt: astroid
+ astroid.brain.brain_ctypes: astroid
+ astroid.brain.brain_curses: astroid
+ astroid.brain.brain_dataclasses: astroid
+ astroid.brain.brain_dateutil: astroid
+ astroid.brain.brain_fstrings: astroid
+ astroid.brain.brain_functools: astroid
+ astroid.brain.brain_gi: astroid
+ astroid.brain.brain_hashlib: astroid
+ astroid.brain.brain_http: astroid
+ astroid.brain.brain_hypothesis: astroid
+ astroid.brain.brain_io: astroid
+ astroid.brain.brain_mechanize: astroid
+ astroid.brain.brain_multiprocessing: astroid
+ astroid.brain.brain_namedtuple_enum: astroid
+ astroid.brain.brain_nose: astroid
+ astroid.brain.brain_numpy_core_einsumfunc: astroid
+ astroid.brain.brain_numpy_core_fromnumeric: astroid
+ astroid.brain.brain_numpy_core_function_base: astroid
+ astroid.brain.brain_numpy_core_multiarray: astroid
+ astroid.brain.brain_numpy_core_numeric: astroid
+ astroid.brain.brain_numpy_core_numerictypes: astroid
+ astroid.brain.brain_numpy_core_umath: astroid
+ astroid.brain.brain_numpy_ma: astroid
+ astroid.brain.brain_numpy_ndarray: astroid
+ astroid.brain.brain_numpy_random_mtrand: astroid
+ astroid.brain.brain_numpy_utils: astroid
+ astroid.brain.brain_pathlib: astroid
+ astroid.brain.brain_pkg_resources: astroid
+ astroid.brain.brain_pytest: astroid
+ astroid.brain.brain_qt: astroid
+ astroid.brain.brain_random: astroid
+ astroid.brain.brain_re: astroid
+ astroid.brain.brain_responses: astroid
+ astroid.brain.brain_scipy_signal: astroid
+ astroid.brain.brain_signal: astroid
+ astroid.brain.brain_six: astroid
+ astroid.brain.brain_sqlalchemy: astroid
+ astroid.brain.brain_ssl: astroid
+ astroid.brain.brain_subprocess: astroid
+ astroid.brain.brain_threading: astroid
+ astroid.brain.brain_type: astroid
+ astroid.brain.brain_typing: astroid
+ astroid.brain.brain_unittest: astroid
+ astroid.brain.brain_uuid: astroid
+ astroid.brain.helpers: astroid
+ astroid.builder: astroid
+ astroid.const: astroid
+ astroid.context: astroid
+ astroid.decorators: astroid
+ astroid.exceptions: astroid
+ astroid.filter_statements: astroid
+ astroid.helpers: astroid
+ astroid.inference: astroid
+ astroid.inference_tip: astroid
+ astroid.interpreter: astroid
+ astroid.interpreter.dunder_lookup: astroid
+ astroid.interpreter.objectmodel: astroid
+ astroid.manager: astroid
+ astroid.mixins: astroid
+ astroid.modutils: astroid
+ astroid.node_classes: astroid
+ astroid.nodes: astroid
+ astroid.nodes.as_string: astroid
+ astroid.nodes.const: astroid
+ astroid.nodes.node_classes: astroid
+ astroid.nodes.node_ng: astroid
+ astroid.nodes.scoped_nodes: astroid
+ astroid.nodes.scoped_nodes.mixin: astroid
+ astroid.nodes.scoped_nodes.scoped_nodes: astroid
+ astroid.nodes.scoped_nodes.utils: astroid
+ astroid.nodes.utils: astroid
+ astroid.objects: astroid
+ astroid.protocols: astroid
+ astroid.raw_building: astroid
+ astroid.rebuilder: astroid
+ astroid.scoped_nodes: astroid
+ astroid.test_utils: astroid
+ astroid.transforms: astroid
+ astroid.typing: astroid
+ astroid.util: astroid
+ certifi: certifi
+ certifi.core: certifi
+ chardet: chardet
+ chardet.big5freq: chardet
+ chardet.big5prober: chardet
+ chardet.chardistribution: chardet
+ chardet.charsetgroupprober: chardet
+ chardet.charsetprober: chardet
+ chardet.cli: chardet
+ chardet.cli.chardetect: chardet
+ chardet.codingstatemachine: chardet
+ chardet.compat: chardet
+ chardet.cp949prober: chardet
+ chardet.enums: chardet
+ chardet.escprober: chardet
+ chardet.escsm: chardet
+ chardet.eucjpprober: chardet
+ chardet.euckrfreq: chardet
+ chardet.euckrprober: chardet
+ chardet.euctwfreq: chardet
+ chardet.euctwprober: chardet
+ chardet.gb2312freq: chardet
+ chardet.gb2312prober: chardet
+ chardet.hebrewprober: chardet
+ chardet.jisfreq: chardet
+ chardet.jpcntx: chardet
+ chardet.langbulgarianmodel: chardet
+ chardet.langgreekmodel: chardet
+ chardet.langhebrewmodel: chardet
+ chardet.langhungarianmodel: chardet
+ chardet.langrussianmodel: chardet
+ chardet.langthaimodel: chardet
+ chardet.langturkishmodel: chardet
+ chardet.latin1prober: chardet
+ chardet.mbcharsetprober: chardet
+ chardet.mbcsgroupprober: chardet
+ chardet.mbcssm: chardet
+ chardet.metadata: chardet
+ chardet.metadata.languages: chardet
+ chardet.sbcharsetprober: chardet
+ chardet.sbcsgroupprober: chardet
+ chardet.sjisprober: chardet
+ chardet.universaldetector: chardet
+ chardet.utf8prober: chardet
+ chardet.version: chardet
+ dateutil: python_dateutil
+ dateutil.easter: python_dateutil
+ dateutil.parser: python_dateutil
+ dateutil.parser.isoparser: python_dateutil
+ dateutil.relativedelta: python_dateutil
+ dateutil.rrule: python_dateutil
+ dateutil.tz: python_dateutil
+ dateutil.tz.tz: python_dateutil
+ dateutil.tz.win: python_dateutil
+ dateutil.tzwin: python_dateutil
+ dateutil.utils: python_dateutil
+ dateutil.zoneinfo: python_dateutil
+ dateutil.zoneinfo.rebuild: python_dateutil
+ dill: dill
+ dill.detect: dill
+ dill.logger: dill
+ dill.objtypes: dill
+ dill.pointers: dill
+ dill.session: dill
+ dill.settings: dill
+ dill.source: dill
+ dill.temp: dill
+ idna: idna
+ idna.codec: idna
+ idna.compat: idna
+ idna.core: idna
+ idna.idnadata: idna
+ idna.intranges: idna
+ idna.package_data: idna
+ idna.uts46data: idna
+ isort: isort
+ isort.api: isort
+ isort.comments: isort
+ isort.core: isort
+ isort.deprecated: isort
+ isort.deprecated.finders: isort
+ isort.exceptions: isort
+ isort.files: isort
+ isort.format: isort
+ isort.hooks: isort
+ isort.identify: isort
+ isort.io: isort
+ isort.literal: isort
+ isort.logo: isort
+ isort.main: isort
+ isort.output: isort
+ isort.parse: isort
+ isort.place: isort
+ isort.profiles: isort
+ isort.pylama_isort: isort
+ isort.sections: isort
+ isort.settings: isort
+ isort.setuptools_commands: isort
+ isort.sorting: isort
+ isort.stdlibs: isort
+ isort.stdlibs.all: isort
+ isort.stdlibs.py2: isort
+ isort.stdlibs.py27: isort
+ isort.stdlibs.py3: isort
+ isort.stdlibs.py310: isort
+ isort.stdlibs.py311: isort
+ isort.stdlibs.py36: isort
+ isort.stdlibs.py37: isort
+ isort.stdlibs.py38: isort
+ isort.stdlibs.py39: isort
+ isort.utils: isort
+ isort.wrap: isort
+ isort.wrap_modes: isort
+ lazy_object_proxy: lazy_object_proxy
+ lazy_object_proxy.compat: lazy_object_proxy
+ lazy_object_proxy.simple: lazy_object_proxy
+ lazy_object_proxy.slots: lazy_object_proxy
+ lazy_object_proxy.utils: lazy_object_proxy
+ magic: python_magic
+ magic.compat: python_magic
+ magic.loader: python_magic
+ mccabe: mccabe
+ pathspec: pathspec
+ pathspec.gitignore: pathspec
+ pathspec.pathspec: pathspec
+ pathspec.pattern: pathspec
+ pathspec.patterns: pathspec
+ pathspec.patterns.gitwildmatch: pathspec
+ pathspec.util: pathspec
+ pkg_resources: setuptools
+ pkg_resources.extern: setuptools
+ platformdirs: platformdirs
+ platformdirs.android: platformdirs
+ platformdirs.api: platformdirs
+ platformdirs.macos: platformdirs
+ platformdirs.unix: platformdirs
+ platformdirs.version: platformdirs
+ platformdirs.windows: platformdirs
+ pylint: pylint
+ pylint.checkers: pylint
+ pylint.checkers.async: pylint
+ pylint.checkers.base: pylint
+ pylint.checkers.base.basic_checker: pylint
+ pylint.checkers.base.basic_error_checker: pylint
+ pylint.checkers.base.comparison_checker: pylint
+ pylint.checkers.base.docstring_checker: pylint
+ pylint.checkers.base.name_checker: pylint
+ pylint.checkers.base.name_checker.checker: pylint
+ pylint.checkers.base.name_checker.naming_style: pylint
+ pylint.checkers.base.pass_checker: pylint
+ pylint.checkers.base_checker: pylint
+ pylint.checkers.classes: pylint
+ pylint.checkers.classes.class_checker: pylint
+ pylint.checkers.classes.special_methods_checker: pylint
+ pylint.checkers.deprecated: pylint
+ pylint.checkers.design_analysis: pylint
+ pylint.checkers.dunder_methods: pylint
+ pylint.checkers.ellipsis_checker: pylint
+ pylint.checkers.exceptions: pylint
+ pylint.checkers.format: pylint
+ pylint.checkers.imports: pylint
+ pylint.checkers.lambda_expressions: pylint
+ pylint.checkers.logging: pylint
+ pylint.checkers.mapreduce_checker: pylint
+ pylint.checkers.method_args: pylint
+ pylint.checkers.misc: pylint
+ pylint.checkers.modified_iterating_checker: pylint
+ pylint.checkers.newstyle: pylint
+ pylint.checkers.non_ascii_names: pylint
+ pylint.checkers.raw_metrics: pylint
+ pylint.checkers.refactoring: pylint
+ pylint.checkers.refactoring.implicit_booleaness_checker: pylint
+ pylint.checkers.refactoring.not_checker: pylint
+ pylint.checkers.refactoring.recommendation_checker: pylint
+ pylint.checkers.refactoring.refactoring_checker: pylint
+ pylint.checkers.similar: pylint
+ pylint.checkers.spelling: pylint
+ pylint.checkers.stdlib: pylint
+ pylint.checkers.strings: pylint
+ pylint.checkers.threading_checker: pylint
+ pylint.checkers.typecheck: pylint
+ pylint.checkers.unicode: pylint
+ pylint.checkers.unsupported_version: pylint
+ pylint.checkers.utils: pylint
+ pylint.checkers.variables: pylint
+ pylint.config: pylint
+ pylint.config.argument: pylint
+ pylint.config.arguments_manager: pylint
+ pylint.config.arguments_provider: pylint
+ pylint.config.callback_actions: pylint
+ pylint.config.config_file_parser: pylint
+ pylint.config.config_initialization: pylint
+ pylint.config.configuration_mixin: pylint
+ pylint.config.deprecation_actions: pylint
+ pylint.config.environment_variable: pylint
+ pylint.config.exceptions: pylint
+ pylint.config.find_default_config_files: pylint
+ pylint.config.help_formatter: pylint
+ pylint.config.option: pylint
+ pylint.config.option_manager_mixin: pylint
+ pylint.config.option_parser: pylint
+ pylint.config.options_provider_mixin: pylint
+ pylint.config.utils: pylint
+ pylint.constants: pylint
+ pylint.epylint: pylint
+ pylint.exceptions: pylint
+ pylint.extensions: pylint
+ pylint.extensions.bad_builtin: pylint
+ pylint.extensions.broad_try_clause: pylint
+ pylint.extensions.check_elif: pylint
+ pylint.extensions.code_style: pylint
+ pylint.extensions.comparetozero: pylint
+ pylint.extensions.comparison_placement: pylint
+ pylint.extensions.confusing_elif: pylint
+ pylint.extensions.consider_ternary_expression: pylint
+ pylint.extensions.docparams: pylint
+ pylint.extensions.docstyle: pylint
+ pylint.extensions.empty_comment: pylint
+ pylint.extensions.emptystring: pylint
+ pylint.extensions.eq_without_hash: pylint
+ pylint.extensions.for_any_all: pylint
+ pylint.extensions.mccabe: pylint
+ pylint.extensions.no_self_use: pylint
+ pylint.extensions.overlapping_exceptions: pylint
+ pylint.extensions.private_import: pylint
+ pylint.extensions.redefined_loop_name: pylint
+ pylint.extensions.redefined_variable_type: pylint
+ pylint.extensions.set_membership: pylint
+ pylint.extensions.typing: pylint
+ pylint.extensions.while_used: pylint
+ pylint.graph: pylint
+ pylint.interfaces: pylint
+ pylint.lint: pylint
+ pylint.lint.base_options: pylint
+ pylint.lint.caching: pylint
+ pylint.lint.expand_modules: pylint
+ pylint.lint.message_state_handler: pylint
+ pylint.lint.parallel: pylint
+ pylint.lint.pylinter: pylint
+ pylint.lint.report_functions: pylint
+ pylint.lint.run: pylint
+ pylint.lint.utils: pylint
+ pylint.message: pylint
+ pylint.message.message: pylint
+ pylint.message.message_definition: pylint
+ pylint.message.message_definition_store: pylint
+ pylint.message.message_id_store: pylint
+ pylint.pyreverse: pylint
+ pylint.pyreverse.diadefslib: pylint
+ pylint.pyreverse.diagrams: pylint
+ pylint.pyreverse.dot_printer: pylint
+ pylint.pyreverse.inspector: pylint
+ pylint.pyreverse.main: pylint
+ pylint.pyreverse.mermaidjs_printer: pylint
+ pylint.pyreverse.plantuml_printer: pylint
+ pylint.pyreverse.printer: pylint
+ pylint.pyreverse.printer_factory: pylint
+ pylint.pyreverse.utils: pylint
+ pylint.pyreverse.vcg_printer: pylint
+ pylint.pyreverse.writer: pylint
+ pylint.reporters: pylint
+ pylint.reporters.base_reporter: pylint
+ pylint.reporters.collecting_reporter: pylint
+ pylint.reporters.json_reporter: pylint
+ pylint.reporters.multi_reporter: pylint
+ pylint.reporters.reports_handler_mix_in: pylint
+ pylint.reporters.text: pylint
+ pylint.reporters.ureports: pylint
+ pylint.reporters.ureports.base_writer: pylint
+ pylint.reporters.ureports.nodes: pylint
+ pylint.reporters.ureports.text_writer: pylint
+ pylint.testutils: pylint
+ pylint.testutils.checker_test_case: pylint
+ pylint.testutils.configuration_test: pylint
+ pylint.testutils.constants: pylint
+ pylint.testutils.decorator: pylint
+ pylint.testutils.functional: pylint
+ pylint.testutils.functional.find_functional_tests: pylint
+ pylint.testutils.functional.lint_module_output_update: pylint
+ pylint.testutils.functional.test_file: pylint
+ pylint.testutils.functional_test_file: pylint
+ pylint.testutils.get_test_info: pylint
+ pylint.testutils.global_test_linter: pylint
+ pylint.testutils.lint_module_test: pylint
+ pylint.testutils.output_line: pylint
+ pylint.testutils.pyreverse: pylint
+ pylint.testutils.reporter_for_tests: pylint
+ pylint.testutils.tokenize_str: pylint
+ pylint.testutils.unittest_linter: pylint
+ pylint.testutils.utils: pylint
+ pylint.typing: pylint
+ pylint.utils: pylint
+ pylint.utils.ast_walker: pylint
+ pylint.utils.docs: pylint
+ pylint.utils.file_state: pylint
+ pylint.utils.linterstats: pylint
+ pylint.utils.pragma_parser: pylint
+ pylint.utils.utils: pylint
+ requests: requests
+ requests.adapters: requests
+ requests.api: requests
+ requests.auth: requests
+ requests.certs: requests
+ requests.compat: requests
+ requests.cookies: requests
+ requests.exceptions: requests
+ requests.help: requests
+ requests.hooks: requests
+ requests.models: requests
+ requests.packages: requests
+ requests.sessions: requests
+ requests.status_codes: requests
+ requests.structures: requests
+ requests.utils: requests
+ setuptools: setuptools
+ setuptools.archive_util: setuptools
+ setuptools.build_meta: setuptools
+ setuptools.command: setuptools
+ setuptools.command.alias: setuptools
+ setuptools.command.bdist_egg: setuptools
+ setuptools.command.bdist_rpm: setuptools
+ setuptools.command.build: setuptools
+ setuptools.command.build_clib: setuptools
+ setuptools.command.build_ext: setuptools
+ setuptools.command.build_py: setuptools
+ setuptools.command.develop: setuptools
+ setuptools.command.dist_info: setuptools
+ setuptools.command.easy_install: setuptools
+ setuptools.command.editable_wheel: setuptools
+ setuptools.command.egg_info: setuptools
+ setuptools.command.install: setuptools
+ setuptools.command.install_egg_info: setuptools
+ setuptools.command.install_lib: setuptools
+ setuptools.command.install_scripts: setuptools
+ setuptools.command.py36compat: setuptools
+ setuptools.command.register: setuptools
+ setuptools.command.rotate: setuptools
+ setuptools.command.saveopts: setuptools
+ setuptools.command.sdist: setuptools
+ setuptools.command.setopt: setuptools
+ setuptools.command.test: setuptools
+ setuptools.command.upload: setuptools
+ setuptools.command.upload_docs: setuptools
+ setuptools.config: setuptools
+ setuptools.config.expand: setuptools
+ setuptools.config.pyprojecttoml: setuptools
+ setuptools.config.setupcfg: setuptools
+ setuptools.dep_util: setuptools
+ setuptools.depends: setuptools
+ setuptools.discovery: setuptools
+ setuptools.dist: setuptools
+ setuptools.errors: setuptools
+ setuptools.extension: setuptools
+ setuptools.extern: setuptools
+ setuptools.glob: setuptools
+ setuptools.installer: setuptools
+ setuptools.launch: setuptools
+ setuptools.logging: setuptools
+ setuptools.monkey: setuptools
+ setuptools.msvc: setuptools
+ setuptools.namespaces: setuptools
+ setuptools.package_index: setuptools
+ setuptools.py34compat: setuptools
+ setuptools.sandbox: setuptools
+ setuptools.unicode_utils: setuptools
+ setuptools.version: setuptools
+ setuptools.wheel: setuptools
+ setuptools.windows_support: setuptools
+ six: six
+ tabulate: tabulate
+ tabulate.version: tabulate
+ tomli: tomli
+ tomlkit: tomlkit
+ tomlkit.api: tomlkit
+ tomlkit.container: tomlkit
+ tomlkit.exceptions: tomlkit
+ tomlkit.items: tomlkit
+ tomlkit.parser: tomlkit
+ tomlkit.source: tomlkit
+ tomlkit.toml_char: tomlkit
+ tomlkit.toml_document: tomlkit
+ tomlkit.toml_file: tomlkit
+ typing_extensions: typing_extensions
+ urllib3: urllib3
+ urllib3.connection: urllib3
+ urllib3.connectionpool: urllib3
+ urllib3.contrib: urllib3
+ urllib3.contrib.appengine: urllib3
+ urllib3.contrib.ntlmpool: urllib3
+ urllib3.contrib.pyopenssl: urllib3
+ urllib3.contrib.securetransport: urllib3
+ urllib3.contrib.socks: urllib3
+ urllib3.exceptions: urllib3
+ urllib3.fields: urllib3
+ urllib3.filepost: urllib3
+ urllib3.packages: urllib3
+ urllib3.packages.backports: urllib3
+ urllib3.packages.backports.makefile: urllib3
+ urllib3.packages.six: urllib3
+ urllib3.poolmanager: urllib3
+ urllib3.request: urllib3
+ urllib3.response: urllib3
+ urllib3.util: urllib3
+ urllib3.util.connection: urllib3
+ urllib3.util.proxy: urllib3
+ urllib3.util.queue: urllib3
+ urllib3.util.request: urllib3
+ urllib3.util.response: urllib3
+ urllib3.util.retry: urllib3
+ urllib3.util.ssl_: urllib3
+ urllib3.util.ssl_match_hostname: urllib3
+ urllib3.util.ssltransport: urllib3
+ urllib3.util.timeout: urllib3
+ urllib3.util.url: urllib3
+ urllib3.util.wait: urllib3
+ wrapt: wrapt
+ wrapt.arguments: wrapt
+ wrapt.decorators: wrapt
+ wrapt.importer: wrapt
+ wrapt.wrappers: wrapt
+ yaml: PyYAML
+ yaml.composer: PyYAML
+ yaml.constructor: PyYAML
+ yaml.cyaml: PyYAML
+ yaml.dumper: PyYAML
+ yaml.emitter: PyYAML
+ yaml.error: PyYAML
+ yaml.events: PyYAML
+ yaml.loader: PyYAML
+ yaml.nodes: PyYAML
+ yaml.parser: PyYAML
+ yaml.reader: PyYAML
+ yaml.representer: PyYAML
+ yaml.resolver: PyYAML
+ yaml.scanner: PyYAML
+ yaml.serializer: PyYAML
+ yaml.tokens: PyYAML
+ yamllint: yamllint
+ yamllint.cli: yamllint
+ yamllint.config: yamllint
+ yamllint.linter: yamllint
+ yamllint.parser: yamllint
+ yamllint.rules: yamllint
+ yamllint.rules.braces: yamllint
+ yamllint.rules.brackets: yamllint
+ yamllint.rules.colons: yamllint
+ yamllint.rules.commas: yamllint
+ yamllint.rules.comments: yamllint
+ yamllint.rules.comments_indentation: yamllint
+ yamllint.rules.common: yamllint
+ yamllint.rules.document_end: yamllint
+ yamllint.rules.document_start: yamllint
+ yamllint.rules.empty_lines: yamllint
+ yamllint.rules.empty_values: yamllint
+ yamllint.rules.float_values: yamllint
+ yamllint.rules.hyphens: yamllint
+ yamllint.rules.indentation: yamllint
+ yamllint.rules.key_duplicates: yamllint
+ yamllint.rules.key_ordering: yamllint
+ yamllint.rules.line_length: yamllint
+ yamllint.rules.new_line_at_end_of_file: yamllint
+ yamllint.rules.new_lines: yamllint
+ yamllint.rules.octal_values: yamllint
+ yamllint.rules.quoted_strings: yamllint
+ yamllint.rules.trailing_spaces: yamllint
+ yamllint.rules.truthy: yamllint
+ pip_repository:
+ name: pip
+ use_pip_repository_aliases: true
+integrity: d979738b10adbbaff0884837e4414688990491c6c40f6a25d58b9bb564411477
diff --git a/examples/bzlmod/requirements_lock.txt b/examples/bzlmod/requirements_lock.txt
index 482402ffb8..2160fe1163 100644
--- a/examples/bzlmod/requirements_lock.txt
+++ b/examples/bzlmod/requirements_lock.txt
@@ -64,12 +64,12 @@ platformdirs==2.6.0 \
pylint==2.15.9 \
--hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 \
--hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb
- # via -r ./requirements.in
+ # via -r requirements.in
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
# via
- # -r ./requirements.in
+ # -r requirements.in
# s3cmd
python-magic==0.4.27 \
--hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \
@@ -120,11 +120,11 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r ./requirements.in
+ # via -r requirements.in
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r ./requirements.in
+ # via -r requirements.in
setuptools==65.6.3 \
--hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
--hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
@@ -136,7 +136,7 @@ six==1.16.0 \
tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
- # via -r ./requirements.in
+ # via -r requirements.in
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
@@ -224,4 +224,4 @@ wrapt==1.14.1 \
yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/examples/bzlmod/requirements_windows.txt b/examples/bzlmod/requirements_windows.txt
index 41187b9475..06cfdc332c 100644
--- a/examples/bzlmod/requirements_windows.txt
+++ b/examples/bzlmod/requirements_windows.txt
@@ -68,12 +68,12 @@ platformdirs==2.6.0 \
pylint==2.15.9 \
--hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 \
--hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb
- # via -r ./requirements.in
+ # via -r requirements.in
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
# via
- # -r ./requirements.in
+ # -r requirements.in
# s3cmd
python-magic==0.4.27 \
--hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \
@@ -124,11 +124,11 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r ./requirements.in
+ # via -r requirements.in
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r ./requirements.in
+ # via -r requirements.in
setuptools==65.6.3 \
--hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
--hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
@@ -140,7 +140,7 @@ six==1.16.0 \
tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
- # via -r ./requirements.in
+ # via -r requirements.in
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
@@ -228,4 +228,4 @@ wrapt==1.14.1 \
yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/examples/bzlmod/runfiles/BUILD.bazel b/examples/bzlmod/runfiles/BUILD.bazel
index add56b3bd0..3503ac3017 100644
--- a/examples/bzlmod/runfiles/BUILD.bazel
+++ b/examples/bzlmod/runfiles/BUILD.bazel
@@ -1,5 +1,6 @@
load("@rules_python//python:defs.bzl", "py_test")
+# gazelle:ignore
py_test(
name = "runfiles_test",
srcs = ["runfiles_test.py"],
diff --git a/examples/bzlmod/test.py b/examples/bzlmod/test.py
index cdc1c89680..a36c19dc63 100644
--- a/examples/bzlmod/test.py
+++ b/examples/bzlmod/test.py
@@ -12,12 +12,57 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
+import pathlib
+import sys
import unittest
from lib import main
class ExampleTest(unittest.TestCase):
+ def test_coverage_doesnt_shadow_stdlib(self):
+ # When we try to import the html module
+ import html as html_stdlib
+
+ try:
+ import coverage.html as html_coverage
+ except ImportError:
+ self.skipTest("not running under coverage, skipping")
+
+ self.assertNotEqual(
+ html_stdlib,
+ html_coverage,
+ "'html' import should not be shadowed by coverage",
+ )
+
+ def test_coverage_sys_path(self):
+ all_paths = ",\n ".join(sys.path)
+
+ for i, path in enumerate(sys.path[1:-2]):
+ self.assertFalse(
+ "/coverage" in path,
+ f"Expected {i + 2}th '{path}' to not contain 'coverage.py' paths, "
+ f"sys.path has {len(sys.path)} items:\n {all_paths}",
+ )
+
+ first_item, last_item = sys.path[0], sys.path[-1]
+ self.assertFalse(
+ first_item.endswith("coverage"),
+ f"Expected the first item in sys.path '{first_item}' to not be related to coverage",
+ )
+ if os.environ.get("COVERAGE_MANIFEST"):
+ # we are running under the 'bazel coverage :test'
+ self.assertTrue(
+ "pypi__coverage_cp" in last_item,
+ f"Expected {last_item} to be related to coverage",
+ )
+ self.assertEqual(pathlib.Path(last_item).name, "coverage")
+ else:
+ self.assertFalse(
+ "coverage" in last_item, f"Expected coverage tooling to not be present"
+ )
+
def test_main(self):
self.assertEquals(
"""\
diff --git a/examples/bzlmod_build_file_generation/.bazelignore b/examples/bzlmod_build_file_generation/.bazelignore
new file mode 100644
index 0000000000..ab3eb1635c
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/.bazelignore
@@ -0,0 +1 @@
+other_module
diff --git a/examples/bzlmod_build_file_generation/.bazelrc b/examples/bzlmod_build_file_generation/.bazelrc
new file mode 100644
index 0000000000..1fbada7ec4
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/.bazelrc
@@ -0,0 +1,9 @@
+test --test_output=errors --enable_runfiles
+
+# Windows requires these for multi-python support:
+build --enable_runfiles
+startup --windows_enable_symlinks
+
+common --experimental_enable_bzlmod
+
+coverage --java_runtime_version=remotejdk_11
diff --git a/examples/bzlmod_build_file_generation/.bazelversion b/examples/bzlmod_build_file_generation/.bazelversion
new file mode 100644
index 0000000000..09b254e90c
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/.bazelversion
@@ -0,0 +1 @@
+6.0.0
diff --git a/examples/bzlmod_build_file_generation/.gitignore b/examples/bzlmod_build_file_generation/.gitignore
new file mode 100644
index 0000000000..ac51a054d2
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/.gitignore
@@ -0,0 +1 @@
+bazel-*
diff --git a/examples/bzlmod_build_file_generation/BUILD.bazel b/examples/bzlmod_build_file_generation/BUILD.bazel
new file mode 100644
index 0000000000..c667f1e49b
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/BUILD.bazel
@@ -0,0 +1,103 @@
+# Load various rules so that we can have bazel download
+# various rulesets and dependencies.
+# The `load` statement imports the symbol for the rule, in the defined
+# ruleset. When the symbol is loaded you can use the rule.
+
+# The following code loads the base python requirements and gazelle
+# requirements.
+load("@bazel_gazelle//:def.bzl", "gazelle")
+load("@pip//:requirements.bzl", "all_whl_requirements")
+load("@python3//:defs.bzl", py_test_with_transition = "py_test")
+load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
+load("@rules_python//python:pip.bzl", "compile_pip_requirements")
+load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
+load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest")
+load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")
+
+# This stanza calls a rule that generates targets for managing pip dependencies
+# with pip-compile.
+compile_pip_requirements(
+ name = "requirements",
+ extra_args = ["--allow-unsafe"],
+ requirements_in = "requirements.in",
+ requirements_txt = "requirements_lock.txt",
+ requirements_windows = "requirements_windows.txt",
+)
+
+# This repository rule fetches the metadata for python packages we
+# depend on. That data is required for the gazelle_python_manifest
+# rule to update our manifest file.
+modules_mapping(
+ name = "modules_map",
+ exclude_patterns = [
+ "^_|(\\._)+", # This is the default.
+ "(\\.tests)+", # Add a custom one to get rid of the psutil tests.
+ ],
+ wheels = all_whl_requirements,
+)
+
+# Gazelle python extension needs a manifest file mapping from
+# an import to the installed package that provides it.
+# This macro produces two targets:
+# - //:gazelle_python_manifest.update can be used with `bazel run`
+# to recalculate the manifest
+# - //:gazelle_python_manifest.test is a test target ensuring that
+# the manifest doesn't need to be updated
+# This target updates a file called gazelle_python.yaml, and
+# requires that file exist before the target is run.
+# When you are using gazelle you need to run this target first.
+gazelle_python_manifest(
+ name = "gazelle_python_manifest",
+ modules_mapping = ":modules_map",
+ pip_repository_name = "pip",
+ requirements = "//:requirements_lock.txt",
+ # NOTE: we can use this flag in order to make our setup compatible with
+ # bzlmod.
+ use_pip_repository_aliases = True,
+)
+
+# Our gazelle target points to the python gazelle binary.
+# This is the simple case where we only need one language supported.
+# If you also had proto, go, or other gazelle-supported languages,
+# you would also need a gazelle_binary rule.
+# See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example
+# This is the primary gazelle target to run, so that you can update BUILD.bazel files.
+# You can execute:
+# - bazel run //:gazelle update
+# - bazel run //:gazelle fix
+# See: https://github.com/bazelbuild/bazel-gazelle#fix-and-update
+gazelle(
+ name = "gazelle",
+ data = GAZELLE_PYTHON_RUNTIME_DEPS,
+ gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary",
+)
+
+py_test_with_transition(
+ name = "test_with_transition",
+ srcs = ["__test__.py"],
+ main = "__test__.py",
+ deps = [":bzlmod_build_file_generation"],
+)
+
+# The following targets are created and maintained by gazelle
+py_library(
+ name = "bzlmod_build_file_generation",
+ srcs = ["lib.py"],
+ visibility = ["//:__subpackages__"],
+ deps = ["@pip//tabulate"],
+)
+
+py_binary(
+ name = "bzlmod_build_file_generation_bin",
+ srcs = ["__main__.py"],
+ main = "__main__.py",
+ visibility = ["//:__subpackages__"],
+ deps = [":bzlmod_build_file_generation"],
+)
+
+py_test(
+ name = "bzlmod_build_file_generation_test",
+ srcs = ["__test__.py"],
+ main = "__test__.py",
+ deps = [":bzlmod_build_file_generation"],
+)
diff --git a/examples/bzlmod_build_file_generation/MODULE.bazel b/examples/bzlmod_build_file_generation/MODULE.bazel
new file mode 100644
index 0000000000..179fe1bdea
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/MODULE.bazel
@@ -0,0 +1,119 @@
+# This file replaces the WORKSPACE file when using bzlmod.
+
+# module declares certain properties of the Bazel module represented by the current Bazel repo.
+# These properties are either essential metadata of the module (such as the name and version),
+# or affect behavior of the current module and its dependents.
+module(
+ name = "example_bzlmod_build_file_generation",
+ version = "0.0.0",
+ compatibility_level = 1,
+)
+
+# The following stanza defines the dependency rules_python.
+# For typical setups you set the version.
+# See the releases page for available versions.
+# https://github.com/bazelbuild/rules_python/releases
+bazel_dep(name = "rules_python", version = "0.0.0")
+
+# The following loads rules_python from the file system.
+# For usual setups you should remove this local_path_override block.
+local_path_override(
+ module_name = "rules_python",
+ path = "../..",
+)
+
+# The following stanza defines the dependency rules_python_gazelle_plugin.
+# For typical setups you set the version.
+# See the releases page for available versions.
+# https://github.com/bazelbuild/rules_python/releases
+bazel_dep(name = "rules_python_gazelle_plugin", version = "0.0.0")
+
+# The following starlark loads the gazelle plugin from the file system.
+# For usual setups you should remove this local_path_override block.
+local_path_override(
+ module_name = "rules_python_gazelle_plugin",
+ path = "../../gazelle",
+)
+
+# The following stanza defines the dependency for gazelle
+# See here https://github.com/bazelbuild/bazel-gazelle/releases/ for the
+# latest version.
+bazel_dep(name = "gazelle", version = "0.30.0", repo_name = "bazel_gazelle")
+
+# The following stanze returns a proxy object representing a module extension;
+# its methods can be invoked to create module extension tags.
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+
+# This name is passed into python.toolchain and it's use_repo statement.
+# We also use the same name for python.host_python_interpreter.
+PYTHON_NAME = "python3"
+
+# We next initialize the python toolchain using the extension.
+# You can set different Python versions in this block.
+python.toolchain(
+ # This name is used in the various use_repo statements
+ # below, and in the local extension that is in this
+ # example.
+ name = PYTHON_NAME,
+ configure_coverage_tool = True,
+ python_version = "3.9",
+)
+
+# Import the python repositories generated by the given module extension
+# into the scope of the current module.
+# All of the python3 repositories use the PYTHON_NAME as there prefix. They
+# are not catenated for ease of reading.
+use_repo(python, PYTHON_NAME, "python3_toolchains")
+
+# Register an already-defined toolchain so that Bazel can use it during
+# toolchain resolution.
+register_toolchains(
+ "@python3_toolchains//:all",
+)
+
+# The interpreter extension discovers the platform specific Python binary.
+# It creates a symlink to the binary, and we pass the label to the following
+# pip.parse call.
+interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter")
+interpreter.install(
+ name = "interpreter_python3",
+ python_name = PYTHON_NAME,
+)
+use_repo(interpreter, "interpreter_python3")
+
+# Use the extension, pip.parse, to call the `pip_repository` rule that invokes
+# `pip`, with `incremental` set. The pip call accepts a locked/compiled
+# requirements file and installs the dependencies listed within.
+# Those dependencies become available in a generated `requirements.bzl` file.
+# You can instead check this `requirements.bzl` file into your repo.
+# Because this project has different requirements for windows vs other
+# operating systems, we have requirements for each.
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+pip.parse(
+ name = "pip",
+ # When using gazelle you must use set the following flag
+ # in order for the generation of gazelle dependency resolution.
+ incompatible_generate_aliases = True,
+ # The interpreter_target attribute points to the interpreter to
+ # use for running pip commands to download the packages in the
+ # requirements file.
+ # As a best practice, we use the same interpreter as the toolchain
+ # that was configured above; this ensures the same Python version
+ # is used for both resolving dependencies and running tests/binaries.
+ # If this isn't specified, then you'll get whatever is locally installed
+ # on your system.
+ python_interpreter_target = "@interpreter_python3//:python",
+ requirements_lock = "//:requirements_lock.txt",
+ requirements_windows = "//:requirements_windows.txt",
+)
+
+# Imports the pip toolchain generated by the given module extension into the scope of the current module.
+use_repo(pip, "pip")
+
+# This project includes a different module that is on the local file system.
+# Add the module to this parent project.
+bazel_dep(name = "other_module", version = "", repo_name = "our_other_module")
+local_path_override(
+ module_name = "other_module",
+ path = "other_module",
+)
diff --git a/examples/bzlmod_build_file_generation/README.md b/examples/bzlmod_build_file_generation/README.md
new file mode 100644
index 0000000000..703fd38ebe
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/README.md
@@ -0,0 +1,28 @@
+# Bzlmod build file generation example
+
+This example demostrates how to use `rules_python` and gazelle with `bzlmod` enabled.
+[Bzlmod](https://bazel.build/external/overview#bzlmod), the new external dependency
+subsystem, does not directly work with repo definitions. Instead, it builds a dependency
+graph from modules, runs extensions on top of the graph, and defines repos accordingly.
+
+Gazelle is setup with the `rules_python`
+extension, so that targets like `py_library` and `py_binary` can be
+automatically created just by running:
+
+```sh
+$ bazel run //:gazelle update
+```
+
+The are other targets that allow you to update the gazelle dependency management
+when you update the requirements.in file. See:
+
+```bash
+bazel run //:gazelle_python_manifest.update
+```
+
+For more information on the behavior of the `rules_python` gazelle extension,
+see the [README.md](../../gazelle/README.md) file in the /gazelle folder.
+
+This example uses a `MODULE.bazel` file that configures the bzlmod dependency
+management. See comments in the `MODULE.bazel` and `BUILD.bazel` files for more
+information.
diff --git a/examples/bzlmod_build_file_generation/WORKSPACE b/examples/bzlmod_build_file_generation/WORKSPACE
new file mode 100644
index 0000000000..78cc252e57
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/WORKSPACE
@@ -0,0 +1,2 @@
+# Empty file indicating the root of a Bazel workspace.
+# Dependencies and setup are in MODULE.bazel.
diff --git a/examples/bzlmod_build_file_generation/__main__.py b/examples/bzlmod_build_file_generation/__main__.py
new file mode 100644
index 0000000000..099493b3c8
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/__main__.py
@@ -0,0 +1,18 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from lib import main
+
+if __name__ == "__main__":
+ print(main([["A", 1], ["B", 2]]))
diff --git a/examples/bzlmod_build_file_generation/__test__.py b/examples/bzlmod_build_file_generation/__test__.py
new file mode 100644
index 0000000000..cdc1c89680
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/__test__.py
@@ -0,0 +1,33 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+
+from lib import main
+
+
+class ExampleTest(unittest.TestCase):
+ def test_main(self):
+ self.assertEquals(
+ """\
+- -
+A 1
+B 2
+- -""",
+ main([["A", 1], ["B", 2]]),
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/examples/bzlmod_build_file_generation/gazelle_python.yaml b/examples/bzlmod_build_file_generation/gazelle_python.yaml
new file mode 100644
index 0000000000..12096e5837
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/gazelle_python.yaml
@@ -0,0 +1,590 @@
+# GENERATED FILE - DO NOT EDIT!
+#
+# To update this file, run:
+# bazel run //:gazelle_python_manifest.update
+
+manifest:
+ modules_mapping:
+ S3: s3cmd
+ S3.ACL: s3cmd
+ S3.AccessLog: s3cmd
+ S3.BidirMap: s3cmd
+ S3.CloudFront: s3cmd
+ S3.Config: s3cmd
+ S3.ConnMan: s3cmd
+ S3.Crypto: s3cmd
+ S3.Custom_httplib27: s3cmd
+ S3.Custom_httplib3x: s3cmd
+ S3.Exceptions: s3cmd
+ S3.ExitCodes: s3cmd
+ S3.FileDict: s3cmd
+ S3.FileLists: s3cmd
+ S3.HashCache: s3cmd
+ S3.MultiPart: s3cmd
+ S3.PkgInfo: s3cmd
+ S3.Progress: s3cmd
+ S3.S3: s3cmd
+ S3.S3Uri: s3cmd
+ S3.SortedDict: s3cmd
+ S3.Utils: s3cmd
+ astroid: astroid
+ astroid.arguments: astroid
+ astroid.astroid_manager: astroid
+ astroid.bases: astroid
+ astroid.brain: astroid
+ astroid.brain.brain_argparse: astroid
+ astroid.brain.brain_attrs: astroid
+ astroid.brain.brain_boto3: astroid
+ astroid.brain.brain_builtin_inference: astroid
+ astroid.brain.brain_collections: astroid
+ astroid.brain.brain_crypt: astroid
+ astroid.brain.brain_ctypes: astroid
+ astroid.brain.brain_curses: astroid
+ astroid.brain.brain_dataclasses: astroid
+ astroid.brain.brain_dateutil: astroid
+ astroid.brain.brain_fstrings: astroid
+ astroid.brain.brain_functools: astroid
+ astroid.brain.brain_gi: astroid
+ astroid.brain.brain_hashlib: astroid
+ astroid.brain.brain_http: astroid
+ astroid.brain.brain_hypothesis: astroid
+ astroid.brain.brain_io: astroid
+ astroid.brain.brain_mechanize: astroid
+ astroid.brain.brain_multiprocessing: astroid
+ astroid.brain.brain_namedtuple_enum: astroid
+ astroid.brain.brain_nose: astroid
+ astroid.brain.brain_numpy_core_einsumfunc: astroid
+ astroid.brain.brain_numpy_core_fromnumeric: astroid
+ astroid.brain.brain_numpy_core_function_base: astroid
+ astroid.brain.brain_numpy_core_multiarray: astroid
+ astroid.brain.brain_numpy_core_numeric: astroid
+ astroid.brain.brain_numpy_core_numerictypes: astroid
+ astroid.brain.brain_numpy_core_umath: astroid
+ astroid.brain.brain_numpy_ma: astroid
+ astroid.brain.brain_numpy_ndarray: astroid
+ astroid.brain.brain_numpy_random_mtrand: astroid
+ astroid.brain.brain_numpy_utils: astroid
+ astroid.brain.brain_pathlib: astroid
+ astroid.brain.brain_pkg_resources: astroid
+ astroid.brain.brain_pytest: astroid
+ astroid.brain.brain_qt: astroid
+ astroid.brain.brain_random: astroid
+ astroid.brain.brain_re: astroid
+ astroid.brain.brain_responses: astroid
+ astroid.brain.brain_scipy_signal: astroid
+ astroid.brain.brain_signal: astroid
+ astroid.brain.brain_six: astroid
+ astroid.brain.brain_sqlalchemy: astroid
+ astroid.brain.brain_ssl: astroid
+ astroid.brain.brain_subprocess: astroid
+ astroid.brain.brain_threading: astroid
+ astroid.brain.brain_type: astroid
+ astroid.brain.brain_typing: astroid
+ astroid.brain.brain_unittest: astroid
+ astroid.brain.brain_uuid: astroid
+ astroid.brain.helpers: astroid
+ astroid.builder: astroid
+ astroid.const: astroid
+ astroid.context: astroid
+ astroid.decorators: astroid
+ astroid.exceptions: astroid
+ astroid.filter_statements: astroid
+ astroid.helpers: astroid
+ astroid.inference: astroid
+ astroid.inference_tip: astroid
+ astroid.interpreter: astroid
+ astroid.interpreter.dunder_lookup: astroid
+ astroid.interpreter.objectmodel: astroid
+ astroid.manager: astroid
+ astroid.mixins: astroid
+ astroid.modutils: astroid
+ astroid.node_classes: astroid
+ astroid.nodes: astroid
+ astroid.nodes.as_string: astroid
+ astroid.nodes.const: astroid
+ astroid.nodes.node_classes: astroid
+ astroid.nodes.node_ng: astroid
+ astroid.nodes.scoped_nodes: astroid
+ astroid.nodes.scoped_nodes.mixin: astroid
+ astroid.nodes.scoped_nodes.scoped_nodes: astroid
+ astroid.nodes.scoped_nodes.utils: astroid
+ astroid.nodes.utils: astroid
+ astroid.objects: astroid
+ astroid.protocols: astroid
+ astroid.raw_building: astroid
+ astroid.rebuilder: astroid
+ astroid.scoped_nodes: astroid
+ astroid.test_utils: astroid
+ astroid.transforms: astroid
+ astroid.typing: astroid
+ astroid.util: astroid
+ certifi: certifi
+ certifi.core: certifi
+ chardet: chardet
+ chardet.big5freq: chardet
+ chardet.big5prober: chardet
+ chardet.chardistribution: chardet
+ chardet.charsetgroupprober: chardet
+ chardet.charsetprober: chardet
+ chardet.cli: chardet
+ chardet.cli.chardetect: chardet
+ chardet.codingstatemachine: chardet
+ chardet.compat: chardet
+ chardet.cp949prober: chardet
+ chardet.enums: chardet
+ chardet.escprober: chardet
+ chardet.escsm: chardet
+ chardet.eucjpprober: chardet
+ chardet.euckrfreq: chardet
+ chardet.euckrprober: chardet
+ chardet.euctwfreq: chardet
+ chardet.euctwprober: chardet
+ chardet.gb2312freq: chardet
+ chardet.gb2312prober: chardet
+ chardet.hebrewprober: chardet
+ chardet.jisfreq: chardet
+ chardet.jpcntx: chardet
+ chardet.langbulgarianmodel: chardet
+ chardet.langgreekmodel: chardet
+ chardet.langhebrewmodel: chardet
+ chardet.langhungarianmodel: chardet
+ chardet.langrussianmodel: chardet
+ chardet.langthaimodel: chardet
+ chardet.langturkishmodel: chardet
+ chardet.latin1prober: chardet
+ chardet.mbcharsetprober: chardet
+ chardet.mbcsgroupprober: chardet
+ chardet.mbcssm: chardet
+ chardet.metadata: chardet
+ chardet.metadata.languages: chardet
+ chardet.sbcharsetprober: chardet
+ chardet.sbcsgroupprober: chardet
+ chardet.sjisprober: chardet
+ chardet.universaldetector: chardet
+ chardet.utf8prober: chardet
+ chardet.version: chardet
+ dateutil: python_dateutil
+ dateutil.easter: python_dateutil
+ dateutil.parser: python_dateutil
+ dateutil.parser.isoparser: python_dateutil
+ dateutil.relativedelta: python_dateutil
+ dateutil.rrule: python_dateutil
+ dateutil.tz: python_dateutil
+ dateutil.tz.tz: python_dateutil
+ dateutil.tz.win: python_dateutil
+ dateutil.tzwin: python_dateutil
+ dateutil.utils: python_dateutil
+ dateutil.zoneinfo: python_dateutil
+ dateutil.zoneinfo.rebuild: python_dateutil
+ dill: dill
+ dill.detect: dill
+ dill.logger: dill
+ dill.objtypes: dill
+ dill.pointers: dill
+ dill.session: dill
+ dill.settings: dill
+ dill.source: dill
+ dill.temp: dill
+ idna: idna
+ idna.codec: idna
+ idna.compat: idna
+ idna.core: idna
+ idna.idnadata: idna
+ idna.intranges: idna
+ idna.package_data: idna
+ idna.uts46data: idna
+ isort: isort
+ isort.api: isort
+ isort.comments: isort
+ isort.core: isort
+ isort.deprecated: isort
+ isort.deprecated.finders: isort
+ isort.exceptions: isort
+ isort.files: isort
+ isort.format: isort
+ isort.hooks: isort
+ isort.identify: isort
+ isort.io: isort
+ isort.literal: isort
+ isort.logo: isort
+ isort.main: isort
+ isort.output: isort
+ isort.parse: isort
+ isort.place: isort
+ isort.profiles: isort
+ isort.pylama_isort: isort
+ isort.sections: isort
+ isort.settings: isort
+ isort.setuptools_commands: isort
+ isort.sorting: isort
+ isort.stdlibs: isort
+ isort.stdlibs.all: isort
+ isort.stdlibs.py2: isort
+ isort.stdlibs.py27: isort
+ isort.stdlibs.py3: isort
+ isort.stdlibs.py310: isort
+ isort.stdlibs.py311: isort
+ isort.stdlibs.py36: isort
+ isort.stdlibs.py37: isort
+ isort.stdlibs.py38: isort
+ isort.stdlibs.py39: isort
+ isort.utils: isort
+ isort.wrap: isort
+ isort.wrap_modes: isort
+ lazy_object_proxy: lazy_object_proxy
+ lazy_object_proxy.compat: lazy_object_proxy
+ lazy_object_proxy.simple: lazy_object_proxy
+ lazy_object_proxy.slots: lazy_object_proxy
+ lazy_object_proxy.utils: lazy_object_proxy
+ magic: python_magic
+ magic.compat: python_magic
+ magic.loader: python_magic
+ mccabe: mccabe
+ pathspec: pathspec
+ pathspec.gitignore: pathspec
+ pathspec.pathspec: pathspec
+ pathspec.pattern: pathspec
+ pathspec.patterns: pathspec
+ pathspec.patterns.gitwildmatch: pathspec
+ pathspec.util: pathspec
+ pkg_resources: setuptools
+ pkg_resources.extern: setuptools
+ platformdirs: platformdirs
+ platformdirs.android: platformdirs
+ platformdirs.api: platformdirs
+ platformdirs.macos: platformdirs
+ platformdirs.unix: platformdirs
+ platformdirs.version: platformdirs
+ platformdirs.windows: platformdirs
+ pylint: pylint
+ pylint.checkers: pylint
+ pylint.checkers.async: pylint
+ pylint.checkers.base: pylint
+ pylint.checkers.base.basic_checker: pylint
+ pylint.checkers.base.basic_error_checker: pylint
+ pylint.checkers.base.comparison_checker: pylint
+ pylint.checkers.base.docstring_checker: pylint
+ pylint.checkers.base.name_checker: pylint
+ pylint.checkers.base.name_checker.checker: pylint
+ pylint.checkers.base.name_checker.naming_style: pylint
+ pylint.checkers.base.pass_checker: pylint
+ pylint.checkers.base_checker: pylint
+ pylint.checkers.classes: pylint
+ pylint.checkers.classes.class_checker: pylint
+ pylint.checkers.classes.special_methods_checker: pylint
+ pylint.checkers.deprecated: pylint
+ pylint.checkers.design_analysis: pylint
+ pylint.checkers.dunder_methods: pylint
+ pylint.checkers.ellipsis_checker: pylint
+ pylint.checkers.exceptions: pylint
+ pylint.checkers.format: pylint
+ pylint.checkers.imports: pylint
+ pylint.checkers.lambda_expressions: pylint
+ pylint.checkers.logging: pylint
+ pylint.checkers.mapreduce_checker: pylint
+ pylint.checkers.method_args: pylint
+ pylint.checkers.misc: pylint
+ pylint.checkers.modified_iterating_checker: pylint
+ pylint.checkers.newstyle: pylint
+ pylint.checkers.non_ascii_names: pylint
+ pylint.checkers.raw_metrics: pylint
+ pylint.checkers.refactoring: pylint
+ pylint.checkers.refactoring.implicit_booleaness_checker: pylint
+ pylint.checkers.refactoring.not_checker: pylint
+ pylint.checkers.refactoring.recommendation_checker: pylint
+ pylint.checkers.refactoring.refactoring_checker: pylint
+ pylint.checkers.similar: pylint
+ pylint.checkers.spelling: pylint
+ pylint.checkers.stdlib: pylint
+ pylint.checkers.strings: pylint
+ pylint.checkers.threading_checker: pylint
+ pylint.checkers.typecheck: pylint
+ pylint.checkers.unicode: pylint
+ pylint.checkers.unsupported_version: pylint
+ pylint.checkers.utils: pylint
+ pylint.checkers.variables: pylint
+ pylint.config: pylint
+ pylint.config.argument: pylint
+ pylint.config.arguments_manager: pylint
+ pylint.config.arguments_provider: pylint
+ pylint.config.callback_actions: pylint
+ pylint.config.config_file_parser: pylint
+ pylint.config.config_initialization: pylint
+ pylint.config.configuration_mixin: pylint
+ pylint.config.deprecation_actions: pylint
+ pylint.config.environment_variable: pylint
+ pylint.config.exceptions: pylint
+ pylint.config.find_default_config_files: pylint
+ pylint.config.help_formatter: pylint
+ pylint.config.option: pylint
+ pylint.config.option_manager_mixin: pylint
+ pylint.config.option_parser: pylint
+ pylint.config.options_provider_mixin: pylint
+ pylint.config.utils: pylint
+ pylint.constants: pylint
+ pylint.epylint: pylint
+ pylint.exceptions: pylint
+ pylint.extensions: pylint
+ pylint.extensions.bad_builtin: pylint
+ pylint.extensions.broad_try_clause: pylint
+ pylint.extensions.check_elif: pylint
+ pylint.extensions.code_style: pylint
+ pylint.extensions.comparetozero: pylint
+ pylint.extensions.comparison_placement: pylint
+ pylint.extensions.confusing_elif: pylint
+ pylint.extensions.consider_ternary_expression: pylint
+ pylint.extensions.docparams: pylint
+ pylint.extensions.docstyle: pylint
+ pylint.extensions.empty_comment: pylint
+ pylint.extensions.emptystring: pylint
+ pylint.extensions.eq_without_hash: pylint
+ pylint.extensions.for_any_all: pylint
+ pylint.extensions.mccabe: pylint
+ pylint.extensions.no_self_use: pylint
+ pylint.extensions.overlapping_exceptions: pylint
+ pylint.extensions.private_import: pylint
+ pylint.extensions.redefined_loop_name: pylint
+ pylint.extensions.redefined_variable_type: pylint
+ pylint.extensions.set_membership: pylint
+ pylint.extensions.typing: pylint
+ pylint.extensions.while_used: pylint
+ pylint.graph: pylint
+ pylint.interfaces: pylint
+ pylint.lint: pylint
+ pylint.lint.base_options: pylint
+ pylint.lint.caching: pylint
+ pylint.lint.expand_modules: pylint
+ pylint.lint.message_state_handler: pylint
+ pylint.lint.parallel: pylint
+ pylint.lint.pylinter: pylint
+ pylint.lint.report_functions: pylint
+ pylint.lint.run: pylint
+ pylint.lint.utils: pylint
+ pylint.message: pylint
+ pylint.message.message: pylint
+ pylint.message.message_definition: pylint
+ pylint.message.message_definition_store: pylint
+ pylint.message.message_id_store: pylint
+ pylint.pyreverse: pylint
+ pylint.pyreverse.diadefslib: pylint
+ pylint.pyreverse.diagrams: pylint
+ pylint.pyreverse.dot_printer: pylint
+ pylint.pyreverse.inspector: pylint
+ pylint.pyreverse.main: pylint
+ pylint.pyreverse.mermaidjs_printer: pylint
+ pylint.pyreverse.plantuml_printer: pylint
+ pylint.pyreverse.printer: pylint
+ pylint.pyreverse.printer_factory: pylint
+ pylint.pyreverse.utils: pylint
+ pylint.pyreverse.vcg_printer: pylint
+ pylint.pyreverse.writer: pylint
+ pylint.reporters: pylint
+ pylint.reporters.base_reporter: pylint
+ pylint.reporters.collecting_reporter: pylint
+ pylint.reporters.json_reporter: pylint
+ pylint.reporters.multi_reporter: pylint
+ pylint.reporters.reports_handler_mix_in: pylint
+ pylint.reporters.text: pylint
+ pylint.reporters.ureports: pylint
+ pylint.reporters.ureports.base_writer: pylint
+ pylint.reporters.ureports.nodes: pylint
+ pylint.reporters.ureports.text_writer: pylint
+ pylint.testutils: pylint
+ pylint.testutils.checker_test_case: pylint
+ pylint.testutils.configuration_test: pylint
+ pylint.testutils.constants: pylint
+ pylint.testutils.decorator: pylint
+ pylint.testutils.functional: pylint
+ pylint.testutils.functional.find_functional_tests: pylint
+ pylint.testutils.functional.lint_module_output_update: pylint
+ pylint.testutils.functional.test_file: pylint
+ pylint.testutils.functional_test_file: pylint
+ pylint.testutils.get_test_info: pylint
+ pylint.testutils.global_test_linter: pylint
+ pylint.testutils.lint_module_test: pylint
+ pylint.testutils.output_line: pylint
+ pylint.testutils.pyreverse: pylint
+ pylint.testutils.reporter_for_tests: pylint
+ pylint.testutils.tokenize_str: pylint
+ pylint.testutils.unittest_linter: pylint
+ pylint.testutils.utils: pylint
+ pylint.typing: pylint
+ pylint.utils: pylint
+ pylint.utils.ast_walker: pylint
+ pylint.utils.docs: pylint
+ pylint.utils.file_state: pylint
+ pylint.utils.linterstats: pylint
+ pylint.utils.pragma_parser: pylint
+ pylint.utils.utils: pylint
+ requests: requests
+ requests.adapters: requests
+ requests.api: requests
+ requests.auth: requests
+ requests.certs: requests
+ requests.compat: requests
+ requests.cookies: requests
+ requests.exceptions: requests
+ requests.help: requests
+ requests.hooks: requests
+ requests.models: requests
+ requests.packages: requests
+ requests.sessions: requests
+ requests.status_codes: requests
+ requests.structures: requests
+ requests.utils: requests
+ setuptools: setuptools
+ setuptools.archive_util: setuptools
+ setuptools.build_meta: setuptools
+ setuptools.command: setuptools
+ setuptools.command.alias: setuptools
+ setuptools.command.bdist_egg: setuptools
+ setuptools.command.bdist_rpm: setuptools
+ setuptools.command.build: setuptools
+ setuptools.command.build_clib: setuptools
+ setuptools.command.build_ext: setuptools
+ setuptools.command.build_py: setuptools
+ setuptools.command.develop: setuptools
+ setuptools.command.dist_info: setuptools
+ setuptools.command.easy_install: setuptools
+ setuptools.command.editable_wheel: setuptools
+ setuptools.command.egg_info: setuptools
+ setuptools.command.install: setuptools
+ setuptools.command.install_egg_info: setuptools
+ setuptools.command.install_lib: setuptools
+ setuptools.command.install_scripts: setuptools
+ setuptools.command.py36compat: setuptools
+ setuptools.command.register: setuptools
+ setuptools.command.rotate: setuptools
+ setuptools.command.saveopts: setuptools
+ setuptools.command.sdist: setuptools
+ setuptools.command.setopt: setuptools
+ setuptools.command.test: setuptools
+ setuptools.command.upload: setuptools
+ setuptools.command.upload_docs: setuptools
+ setuptools.config: setuptools
+ setuptools.config.expand: setuptools
+ setuptools.config.pyprojecttoml: setuptools
+ setuptools.config.setupcfg: setuptools
+ setuptools.dep_util: setuptools
+ setuptools.depends: setuptools
+ setuptools.discovery: setuptools
+ setuptools.dist: setuptools
+ setuptools.errors: setuptools
+ setuptools.extension: setuptools
+ setuptools.extern: setuptools
+ setuptools.glob: setuptools
+ setuptools.installer: setuptools
+ setuptools.launch: setuptools
+ setuptools.logging: setuptools
+ setuptools.monkey: setuptools
+ setuptools.msvc: setuptools
+ setuptools.namespaces: setuptools
+ setuptools.package_index: setuptools
+ setuptools.py34compat: setuptools
+ setuptools.sandbox: setuptools
+ setuptools.unicode_utils: setuptools
+ setuptools.version: setuptools
+ setuptools.wheel: setuptools
+ setuptools.windows_support: setuptools
+ six: six
+ tabulate: tabulate
+ tabulate.version: tabulate
+ tomli: tomli
+ tomlkit: tomlkit
+ tomlkit.api: tomlkit
+ tomlkit.container: tomlkit
+ tomlkit.exceptions: tomlkit
+ tomlkit.items: tomlkit
+ tomlkit.parser: tomlkit
+ tomlkit.source: tomlkit
+ tomlkit.toml_char: tomlkit
+ tomlkit.toml_document: tomlkit
+ tomlkit.toml_file: tomlkit
+ typing_extensions: typing_extensions
+ urllib3: urllib3
+ urllib3.connection: urllib3
+ urllib3.connectionpool: urllib3
+ urllib3.contrib: urllib3
+ urllib3.contrib.appengine: urllib3
+ urllib3.contrib.ntlmpool: urllib3
+ urllib3.contrib.pyopenssl: urllib3
+ urllib3.contrib.securetransport: urllib3
+ urllib3.contrib.socks: urllib3
+ urllib3.exceptions: urllib3
+ urllib3.fields: urllib3
+ urllib3.filepost: urllib3
+ urllib3.packages: urllib3
+ urllib3.packages.backports: urllib3
+ urllib3.packages.backports.makefile: urllib3
+ urllib3.packages.six: urllib3
+ urllib3.poolmanager: urllib3
+ urllib3.request: urllib3
+ urllib3.response: urllib3
+ urllib3.util: urllib3
+ urllib3.util.connection: urllib3
+ urllib3.util.proxy: urllib3
+ urllib3.util.queue: urllib3
+ urllib3.util.request: urllib3
+ urllib3.util.response: urllib3
+ urllib3.util.retry: urllib3
+ urllib3.util.ssl_: urllib3
+ urllib3.util.ssl_match_hostname: urllib3
+ urllib3.util.ssltransport: urllib3
+ urllib3.util.timeout: urllib3
+ urllib3.util.url: urllib3
+ urllib3.util.wait: urllib3
+ wrapt: wrapt
+ wrapt.arguments: wrapt
+ wrapt.decorators: wrapt
+ wrapt.importer: wrapt
+ wrapt.wrappers: wrapt
+ yaml: PyYAML
+ yaml.composer: PyYAML
+ yaml.constructor: PyYAML
+ yaml.cyaml: PyYAML
+ yaml.dumper: PyYAML
+ yaml.emitter: PyYAML
+ yaml.error: PyYAML
+ yaml.events: PyYAML
+ yaml.loader: PyYAML
+ yaml.nodes: PyYAML
+ yaml.parser: PyYAML
+ yaml.reader: PyYAML
+ yaml.representer: PyYAML
+ yaml.resolver: PyYAML
+ yaml.scanner: PyYAML
+ yaml.serializer: PyYAML
+ yaml.tokens: PyYAML
+ yamllint: yamllint
+ yamllint.cli: yamllint
+ yamllint.config: yamllint
+ yamllint.linter: yamllint
+ yamllint.parser: yamllint
+ yamllint.rules: yamllint
+ yamllint.rules.braces: yamllint
+ yamllint.rules.brackets: yamllint
+ yamllint.rules.colons: yamllint
+ yamllint.rules.commas: yamllint
+ yamllint.rules.comments: yamllint
+ yamllint.rules.comments_indentation: yamllint
+ yamllint.rules.common: yamllint
+ yamllint.rules.document_end: yamllint
+ yamllint.rules.document_start: yamllint
+ yamllint.rules.empty_lines: yamllint
+ yamllint.rules.empty_values: yamllint
+ yamllint.rules.float_values: yamllint
+ yamllint.rules.hyphens: yamllint
+ yamllint.rules.indentation: yamllint
+ yamllint.rules.key_duplicates: yamllint
+ yamllint.rules.key_ordering: yamllint
+ yamllint.rules.line_length: yamllint
+ yamllint.rules.new_line_at_end_of_file: yamllint
+ yamllint.rules.new_lines: yamllint
+ yamllint.rules.octal_values: yamllint
+ yamllint.rules.quoted_strings: yamllint
+ yamllint.rules.trailing_spaces: yamllint
+ yamllint.rules.truthy: yamllint
+ pip_repository:
+ name: pip
+ use_pip_repository_aliases: true
+integrity: d979738b10adbbaff0884837e4414688990491c6c40f6a25d58b9bb564411477
diff --git a/examples/bzlmod_build_file_generation/lib.py b/examples/bzlmod_build_file_generation/lib.py
new file mode 100644
index 0000000000..646c6e890f
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/lib.py
@@ -0,0 +1,19 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from tabulate import tabulate
+
+
+def main(table):
+ return tabulate(table)
diff --git a/examples/bzlmod_build_file_generation/other_module/MODULE.bazel b/examples/bzlmod_build_file_generation/other_module/MODULE.bazel
new file mode 100644
index 0000000000..992e120760
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/other_module/MODULE.bazel
@@ -0,0 +1,5 @@
+module(
+ name = "other_module",
+)
+
+bazel_dep(name = "rules_python", version = "")
diff --git a/examples/bzlmod_build_file_generation/other_module/WORKSPACE b/examples/bzlmod_build_file_generation/other_module/WORKSPACE
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/bzlmod_build_file_generation/other_module/other_module/pkg/BUILD.bazel b/examples/bzlmod_build_file_generation/other_module/other_module/pkg/BUILD.bazel
new file mode 100644
index 0000000000..9a130e3554
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/other_module/other_module/pkg/BUILD.bazel
@@ -0,0 +1,11 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+py_library(
+ name = "lib",
+ srcs = ["lib.py"],
+ data = ["data/data.txt"],
+ visibility = ["//visibility:public"],
+ deps = ["@rules_python//python/runfiles"],
+)
+
+exports_files(["data/data.txt"])
diff --git a/examples/bzlmod_build_file_generation/other_module/other_module/pkg/data/data.txt b/examples/bzlmod_build_file_generation/other_module/other_module/pkg/data/data.txt
new file mode 100644
index 0000000000..e975eaf640
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/other_module/other_module/pkg/data/data.txt
@@ -0,0 +1 @@
+Hello, other_module!
diff --git a/examples/bzlmod_build_file_generation/other_module/other_module/pkg/lib.py b/examples/bzlmod_build_file_generation/other_module/other_module/pkg/lib.py
new file mode 100644
index 0000000000..eaf65fb46a
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/other_module/other_module/pkg/lib.py
@@ -0,0 +1,27 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from python.runfiles import runfiles
+
+
+def GetRunfilePathWithCurrentRepository():
+ r = runfiles.Create()
+ own_repo = r.CurrentRepository()
+ # For a non-main repository, the name of the runfiles directory is equal to
+ # the canonical repository name.
+ return r.Rlocation(own_repo + "/other_module/pkg/data/data.txt")
+
+
+def GetRunfilePathWithRepoMapping():
+ return runfiles.Create().Rlocation("other_module/other_module/pkg/data/data.txt")
diff --git a/examples/bzlmod_build_file_generation/requirements.in b/examples/bzlmod_build_file_generation/requirements.in
new file mode 100644
index 0000000000..a709195442
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/requirements.in
@@ -0,0 +1,6 @@
+requests~=2.25.1
+s3cmd~=2.1.0
+yamllint>=1.28.0
+tabulate~=0.9.0
+pylint~=2.15.5
+python-dateutil>=2.8.2
diff --git a/examples/bzlmod_build_file_generation/requirements_lock.txt b/examples/bzlmod_build_file_generation/requirements_lock.txt
new file mode 100644
index 0000000000..2160fe1163
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/requirements_lock.txt
@@ -0,0 +1,227 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# bazel run //:requirements.update
+#
+astroid==2.12.13 \
+ --hash=sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907 \
+ --hash=sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7
+ # via pylint
+certifi==2022.12.7 \
+ --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
+ --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
+ # via requests
+chardet==4.0.0 \
+ --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
+ --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
+ # via requests
+dill==0.3.6 \
+ --hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
+ --hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
+ # via pylint
+idna==2.10 \
+ --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
+ --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
+ # via requests
+isort==5.11.4 \
+ --hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 \
+ --hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b
+ # via pylint
+lazy-object-proxy==1.8.0 \
+ --hash=sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada \
+ --hash=sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d \
+ --hash=sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7 \
+ --hash=sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe \
+ --hash=sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd \
+ --hash=sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c \
+ --hash=sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858 \
+ --hash=sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288 \
+ --hash=sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec \
+ --hash=sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f \
+ --hash=sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891 \
+ --hash=sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c \
+ --hash=sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25 \
+ --hash=sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156 \
+ --hash=sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8 \
+ --hash=sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f \
+ --hash=sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e \
+ --hash=sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0 \
+ --hash=sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b
+ # via astroid
+mccabe==0.7.0 \
+ --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
+ --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
+ # via pylint
+pathspec==0.10.3 \
+ --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
+ --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
+ # via yamllint
+platformdirs==2.6.0 \
+ --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \
+ --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e
+ # via pylint
+pylint==2.15.9 \
+ --hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 \
+ --hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb
+ # via -r requirements.in
+python-dateutil==2.8.2 \
+ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
+ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
+ # via
+ # -r requirements.in
+ # s3cmd
+python-magic==0.4.27 \
+ --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \
+ --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3
+ # via s3cmd
+pyyaml==6.0 \
+ --hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \
+ --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \
+ --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \
+ --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \
+ --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \
+ --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \
+ --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \
+ --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \
+ --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \
+ --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \
+ --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
+ --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \
+ --hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \
+ --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \
+ --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
+ --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
+ --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \
+ --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \
+ --hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \
+ --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \
+ --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
+ --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \
+ --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
+ --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \
+ --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \
+ --hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \
+ --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \
+ --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \
+ --hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \
+ --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \
+ --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \
+ --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \
+ --hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \
+ --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
+ --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \
+ --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \
+ --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
+ --hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \
+ --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
+ --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
+ # via yamllint
+requests==2.25.1 \
+ --hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
+ --hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
+ # via -r requirements.in
+s3cmd==2.1.0 \
+ --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
+ --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
+ # via -r requirements.in
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
+six==1.16.0 \
+ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+ # via python-dateutil
+tabulate==0.9.0 \
+ --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
+ --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
+ # via -r requirements.in
+tomli==2.0.1 \
+ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+ # via pylint
+tomlkit==0.11.6 \
+ --hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \
+ --hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73
+ # via pylint
+typing-extensions==4.4.0 \
+ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \
+ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e
+ # via
+ # astroid
+ # pylint
+urllib3==1.26.13 \
+ --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
+ --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
+ # via requests
+wrapt==1.14.1 \
+ --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \
+ --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \
+ --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \
+ --hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \
+ --hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \
+ --hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \
+ --hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \
+ --hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \
+ --hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \
+ --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \
+ --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \
+ --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \
+ --hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \
+ --hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \
+ --hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \
+ --hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \
+ --hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \
+ --hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \
+ --hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \
+ --hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \
+ --hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \
+ --hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \
+ --hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \
+ --hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \
+ --hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \
+ --hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \
+ --hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \
+ --hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \
+ --hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \
+ --hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \
+ --hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \
+ --hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \
+ --hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \
+ --hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \
+ --hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \
+ --hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \
+ --hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \
+ --hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \
+ --hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \
+ --hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \
+ --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \
+ --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \
+ --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \
+ --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \
+ --hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \
+ --hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \
+ --hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \
+ --hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \
+ --hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \
+ --hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \
+ --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \
+ --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \
+ --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \
+ --hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \
+ --hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \
+ --hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \
+ --hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \
+ --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \
+ --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \
+ --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \
+ --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \
+ --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \
+ --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \
+ --hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af
+ # via astroid
+yamllint==1.28.0 \
+ --hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
+ --hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
+ # via -r requirements.in
diff --git a/examples/bzlmod_build_file_generation/requirements_windows.txt b/examples/bzlmod_build_file_generation/requirements_windows.txt
new file mode 100644
index 0000000000..06cfdc332c
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/requirements_windows.txt
@@ -0,0 +1,231 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# bazel run //:requirements.update
+#
+astroid==2.12.13 \
+ --hash=sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907 \
+ --hash=sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7
+ # via pylint
+certifi==2022.12.7 \
+ --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
+ --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
+ # via requests
+chardet==4.0.0 \
+ --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
+ --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
+ # via requests
+colorama==0.4.6 \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+ # via pylint
+dill==0.3.6 \
+ --hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
+ --hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
+ # via pylint
+idna==2.10 \
+ --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
+ --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
+ # via requests
+isort==5.11.4 \
+ --hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 \
+ --hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b
+ # via pylint
+lazy-object-proxy==1.8.0 \
+ --hash=sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada \
+ --hash=sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d \
+ --hash=sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7 \
+ --hash=sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe \
+ --hash=sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd \
+ --hash=sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c \
+ --hash=sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858 \
+ --hash=sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288 \
+ --hash=sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec \
+ --hash=sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f \
+ --hash=sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891 \
+ --hash=sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c \
+ --hash=sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25 \
+ --hash=sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156 \
+ --hash=sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8 \
+ --hash=sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f \
+ --hash=sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e \
+ --hash=sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0 \
+ --hash=sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b
+ # via astroid
+mccabe==0.7.0 \
+ --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
+ --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
+ # via pylint
+pathspec==0.10.3 \
+ --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
+ --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
+ # via yamllint
+platformdirs==2.6.0 \
+ --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \
+ --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e
+ # via pylint
+pylint==2.15.9 \
+ --hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 \
+ --hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb
+ # via -r requirements.in
+python-dateutil==2.8.2 \
+ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
+ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
+ # via
+ # -r requirements.in
+ # s3cmd
+python-magic==0.4.27 \
+ --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \
+ --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3
+ # via s3cmd
+pyyaml==6.0 \
+ --hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \
+ --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \
+ --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \
+ --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \
+ --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \
+ --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \
+ --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \
+ --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \
+ --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \
+ --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \
+ --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
+ --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \
+ --hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \
+ --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \
+ --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
+ --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
+ --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \
+ --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \
+ --hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \
+ --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \
+ --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
+ --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \
+ --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
+ --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \
+ --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \
+ --hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \
+ --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \
+ --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \
+ --hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \
+ --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \
+ --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \
+ --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \
+ --hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \
+ --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
+ --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \
+ --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \
+ --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
+ --hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \
+ --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
+ --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
+ # via yamllint
+requests==2.25.1 \
+ --hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
+ --hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
+ # via -r requirements.in
+s3cmd==2.1.0 \
+ --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
+ --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
+ # via -r requirements.in
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
+six==1.16.0 \
+ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+ # via python-dateutil
+tabulate==0.9.0 \
+ --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
+ --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
+ # via -r requirements.in
+tomli==2.0.1 \
+ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+ # via pylint
+tomlkit==0.11.6 \
+ --hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \
+ --hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73
+ # via pylint
+typing-extensions==4.4.0 \
+ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \
+ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e
+ # via
+ # astroid
+ # pylint
+urllib3==1.26.13 \
+ --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
+ --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
+ # via requests
+wrapt==1.14.1 \
+ --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \
+ --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \
+ --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \
+ --hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \
+ --hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \
+ --hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \
+ --hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \
+ --hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \
+ --hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \
+ --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \
+ --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \
+ --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \
+ --hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \
+ --hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \
+ --hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \
+ --hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \
+ --hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \
+ --hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \
+ --hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \
+ --hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \
+ --hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \
+ --hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \
+ --hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \
+ --hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \
+ --hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \
+ --hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \
+ --hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \
+ --hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \
+ --hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \
+ --hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \
+ --hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \
+ --hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \
+ --hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \
+ --hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \
+ --hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \
+ --hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \
+ --hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \
+ --hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \
+ --hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \
+ --hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \
+ --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \
+ --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \
+ --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \
+ --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \
+ --hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \
+ --hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \
+ --hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \
+ --hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \
+ --hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \
+ --hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \
+ --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \
+ --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \
+ --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \
+ --hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \
+ --hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \
+ --hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \
+ --hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \
+ --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \
+ --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \
+ --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \
+ --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \
+ --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \
+ --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \
+ --hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af
+ # via astroid
+yamllint==1.28.0 \
+ --hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
+ --hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
+ # via -r requirements.in
diff --git a/examples/bzlmod_build_file_generation/runfiles/BUILD.bazel b/examples/bzlmod_build_file_generation/runfiles/BUILD.bazel
new file mode 100644
index 0000000000..3503ac3017
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/runfiles/BUILD.bazel
@@ -0,0 +1,19 @@
+load("@rules_python//python:defs.bzl", "py_test")
+
+# gazelle:ignore
+py_test(
+ name = "runfiles_test",
+ srcs = ["runfiles_test.py"],
+ data = [
+ "data/data.txt",
+ "@our_other_module//other_module/pkg:data/data.txt",
+ ],
+ env = {
+ "DATA_RLOCATIONPATH": "$(rlocationpath data/data.txt)",
+ "OTHER_MODULE_DATA_RLOCATIONPATH": "$(rlocationpath @our_other_module//other_module/pkg:data/data.txt)",
+ },
+ deps = [
+ "@our_other_module//other_module/pkg:lib",
+ "@rules_python//python/runfiles",
+ ],
+)
diff --git a/examples/bzlmod_build_file_generation/runfiles/data/data.txt b/examples/bzlmod_build_file_generation/runfiles/data/data.txt
new file mode 100644
index 0000000000..fb17e0df66
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/runfiles/data/data.txt
@@ -0,0 +1 @@
+Hello, example_bzlmod!
diff --git a/examples/bzlmod_build_file_generation/runfiles/runfiles_test.py b/examples/bzlmod_build_file_generation/runfiles/runfiles_test.py
new file mode 100644
index 0000000000..a588040cfd
--- /dev/null
+++ b/examples/bzlmod_build_file_generation/runfiles/runfiles_test.py
@@ -0,0 +1,64 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import unittest
+
+from other_module.pkg import lib
+
+from python.runfiles import runfiles
+
+
+class RunfilesTest(unittest.TestCase):
+ # """Unit tests for `runfiles.Runfiles`."""
+ def testCurrentRepository(self):
+ self.assertEqual(runfiles.Create().CurrentRepository(), "")
+
+ def testRunfilesWithRepoMapping(self):
+ data_path = runfiles.Create().Rlocation("example_bzlmod_build_file_generation/runfiles/data/data.txt")
+ with open(data_path) as f:
+ self.assertEqual(f.read().strip(), "Hello, example_bzlmod!")
+
+ def testRunfileWithRlocationpath(self):
+ data_rlocationpath = os.getenv("DATA_RLOCATIONPATH")
+ data_path = runfiles.Create().Rlocation(data_rlocationpath)
+ with open(data_path) as f:
+ self.assertEqual(f.read().strip(), "Hello, example_bzlmod!")
+
+ def testRunfileInOtherModuleWithOurRepoMapping(self):
+ data_path = runfiles.Create().Rlocation(
+ "our_other_module/other_module/pkg/data/data.txt"
+ )
+ with open(data_path) as f:
+ self.assertEqual(f.read().strip(), "Hello, other_module!")
+
+ def testRunfileInOtherModuleWithItsRepoMapping(self):
+ data_path = lib.GetRunfilePathWithRepoMapping()
+ with open(data_path) as f:
+ self.assertEqual(f.read().strip(), "Hello, other_module!")
+
+ def testRunfileInOtherModuleWithCurrentRepository(self):
+ data_path = lib.GetRunfilePathWithCurrentRepository()
+ with open(data_path) as f:
+ self.assertEqual(f.read().strip(), "Hello, other_module!")
+
+ def testRunfileInOtherModuleWithRlocationpath(self):
+ data_rlocationpath = os.getenv("OTHER_MODULE_DATA_RLOCATIONPATH")
+ data_path = runfiles.Create().Rlocation(data_rlocationpath)
+ with open(data_path) as f:
+ self.assertEqual(f.read().strip(), "Hello, other_module!")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/examples/pip_install/requirements.txt b/examples/pip_install/requirements.txt
index ca8d5943a7..495a32a637 100644
--- a/examples/pip_install/requirements.txt
+++ b/examples/pip_install/requirements.txt
@@ -7,7 +7,7 @@
boto3==1.14.63 \
--hash=sha256:25c716b7c01d4664027afc6a6418a06459e311a610c7fd39a030a1ced1b72ce4 \
--hash=sha256:37158c37a151eab5b9080968305621a40168171fda9584d50a309ceb4e5e6964
- # via -r ./requirements.in
+ # via -r requirements.in
botocore==1.17.63 \
--hash=sha256:40f13f6c9c29c307a9dc5982739e537ddce55b29787b90c3447b507e3283bcd6 \
--hash=sha256:aa88eafc6295132f4bc606f1df32b3248e0fa611724c0a216aceda767948ac75
@@ -84,7 +84,7 @@ pyyaml==6.0 \
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r ./requirements.in
+ # via -r requirements.in
s3transfer==0.3.7 \
--hash=sha256:35627b86af8ff97e7ac27975fe0a98a312814b46c6333d8a6b889627bcd80994 \
--hash=sha256:efa5bd92a897b6a8d5c1383828dca3d52d0790e0756d49740563a3fb6ed03246
@@ -100,11 +100,11 @@ six==1.16.0 \
tree-sitter==0.20.0 ; sys_platform != "win32" \
--hash=sha256:1940f64be1e8c9c3c0e34a2258f1e4c324207534d5b1eefc5ab2960a9d98f668 \
--hash=sha256:51a609a7c1bd9d9e75d92ee128c12c7852ae70a482900fbbccf3d13a79e0378c
- # via -r ./requirements.in
+ # via -r requirements.in
urllib3==1.25.11 \
--hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
--hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e
# via botocore
yamllint==1.26.3 \
--hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/examples/pip_install/requirements_windows.txt b/examples/pip_install/requirements_windows.txt
index c4279cb6d7..b87192f9d0 100644
--- a/examples/pip_install/requirements_windows.txt
+++ b/examples/pip_install/requirements_windows.txt
@@ -7,7 +7,7 @@
boto3==1.14.63 \
--hash=sha256:25c716b7c01d4664027afc6a6418a06459e311a610c7fd39a030a1ced1b72ce4 \
--hash=sha256:37158c37a151eab5b9080968305621a40168171fda9584d50a309ceb4e5e6964
- # via -r ./requirements.in
+ # via -r requirements.in
botocore==1.17.63 \
--hash=sha256:40f13f6c9c29c307a9dc5982739e537ddce55b29787b90c3447b507e3283bcd6 \
--hash=sha256:aa88eafc6295132f4bc606f1df32b3248e0fa611724c0a216aceda767948ac75
@@ -84,7 +84,7 @@ pyyaml==6.0 \
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r ./requirements.in
+ # via -r requirements.in
s3transfer==0.3.7 \
--hash=sha256:35627b86af8ff97e7ac27975fe0a98a312814b46c6333d8a6b889627bcd80994 \
--hash=sha256:efa5bd92a897b6a8d5c1383828dca3d52d0790e0756d49740563a3fb6ed03246
@@ -103,4 +103,4 @@ urllib3==1.25.11 \
# via botocore
yamllint==1.26.3 \
--hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/examples/pip_parse/requirements_lock.txt b/examples/pip_parse/requirements_lock.txt
index d60295c0bf..3cbe57f28c 100644
--- a/examples/pip_parse/requirements_lock.txt
+++ b/examples/pip_parse/requirements_lock.txt
@@ -73,11 +73,11 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r ./requirements.in
+ # via -r requirements.in
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r ./requirements.in
+ # via -r requirements.in
setuptools==65.6.3 \
--hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
--hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
@@ -92,4 +92,4 @@ urllib3==1.26.13 \
# via requests
yamllint==1.26.3 \
--hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/examples/pip_parse_vendored/requirements.txt b/examples/pip_parse_vendored/requirements.txt
index 6a70e036b4..ff1a3633a2 100644
--- a/examples/pip_parse_vendored/requirements.txt
+++ b/examples/pip_parse_vendored/requirements.txt
@@ -19,7 +19,7 @@ idna==3.4 \
requests==2.28.1 \
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
- # via -r ./requirements.in
+ # via -r requirements.in
urllib3==1.26.13 \
--hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
--hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
diff --git a/examples/pip_repository_annotations/requirements.txt b/examples/pip_repository_annotations/requirements.txt
index f599f7a457..9fde0a922f 100644
--- a/examples/pip_repository_annotations/requirements.txt
+++ b/examples/pip_repository_annotations/requirements.txt
@@ -21,7 +21,7 @@ idna==3.4 \
requests[security]==2.28.1 \
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
- # via -r ./requirements.in
+ # via -r requirements.in
urllib3==1.26.13 \
--hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
--hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
@@ -29,4 +29,4 @@ urllib3==1.26.13 \
wheel==0.38.4 \
--hash=sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac \
--hash=sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/examples/py_proto_library/MODULE.bazel b/examples/py_proto_library/MODULE.bazel
index 5ce0924a99..6fb1a05548 100644
--- a/examples/py_proto_library/MODULE.bazel
+++ b/examples/py_proto_library/MODULE.bazel
@@ -12,7 +12,7 @@ local_path_override(
path = "../..",
)
-python = use_extension("@rules_python//python:extensions.bzl", "python")
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
name = "python3_9",
configure_coverage_tool = True,
diff --git a/gazelle/README.md b/gazelle/README.md
index e9a8052353..e36f3a303a 100644
--- a/gazelle/README.md
+++ b/gazelle/README.md
@@ -15,7 +15,10 @@ without using bzlmod as your dependency manager.
## Example
-We have an example of using Gazelle with Python located [here](https://github.com/bazelbuild/rules_python/tree/main/examples/build_file_generation).
+We have an example of using Gazelle with Python located [here](https://github.com/bazelbuild/rules_python/tree/main/examples/bzlmod).
+A fully-working example without using bzlmod is in [`examples/build_file_generation`](../examples/build_file_generation).
+
+The following documentation covers using bzlmod.
## Adding Gazelle to your project
@@ -40,10 +43,37 @@ bazel_dep(name = "rules_python_gazelle_plugin", version = "0.20.0")
# The following stanza defines the dependency rules_python.
bazel_dep(name = "gazelle", version = "0.30.0", repo_name = "bazel_gazelle")
-```
-You will also need to do the other usual configuration for `rules_python` in your
-`MODULE.bazel` file.
+# Import the python repositories generated by the given module extension into the scope of the current module.
+use_repo(python, "python3_9")
+use_repo(python, "python3_9_toolchains")
+
+# Register an already-defined toolchain so that Bazel can use it during toolchain resolution.
+register_toolchains(
+ "@python3_9_toolchains//:all",
+)
+
+# Use the pip extension
+pip = use_extension("@rules_python//python:extensions.bzl", "pip")
+
+# Use the extension to call the `pip_repository` rule that invokes `pip`, with `incremental` set.
+# Accepts a locked/compiled requirements file and installs the dependencies listed within.
+# Those dependencies become available in a generated `requirements.bzl` file.
+# You can instead check this `requirements.bzl` file into your repo.
+# Because this project has different requirements for windows vs other
+# operating systems, we have requirements for each.
+pip.parse(
+ name = "pip",
+ # When using gazelle you must use set the following flag
+ # in order for the generation of gazelle dependency resolution.
+ incompatible_generate_aliases = True,
+ requirements_lock = "//:requirements_lock.txt",
+ requirements_windows = "//:requirements_windows.txt",
+)
+
+# Imports the pip toolchain generated by the given module extension into the scope of the current module.
+use_repo(pip, "pip")
+```
Next, we'll fetch metadata about your Python dependencies, so that gazelle can
determine which package a given import statement comes from. This is provided
by the `modules_mapping` rule. We'll make a target for consuming this
@@ -86,6 +116,9 @@ gazelle_python_manifest(
# This should point to wherever we declare our python dependencies
# (the same as what we passed to the modules_mapping rule in WORKSPACE)
requirements = "//:requirements_lock.txt",
+ # NOTE: we can use this flag in order to make our setup compatible with
+ # bzlmod.
+ use_pip_repository_aliases = True,
)
```
@@ -93,7 +126,7 @@ Finally, you create a target that you'll invoke to run the Gazelle tool
with the rules_python extension included. This typically goes in your root
`/BUILD.bazel` file:
-```
+```starlark
load("@bazel_gazelle//:def.bzl", "gazelle")
load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
@@ -112,8 +145,6 @@ gazelle(
That's it, now you can finally run `bazel run //:gazelle` anytime
you edit Python code, and it should update your `BUILD` files correctly.
-A fully-working example is in [`examples/build_file_generation`](../examples/build_file_generation).
-
## Usage
Gazelle is non-destructive.
diff --git a/internal_deps.bzl b/internal_deps.bzl
index 8f52b0e7d7..e4d2f69d41 100644
--- a/internal_deps.bzl
+++ b/internal_deps.bzl
@@ -20,6 +20,9 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
def rules_python_internal_deps():
"""Fetches all required dependencies for rules_python tests and tools."""
+ # This version is also used in python/tests/toolchains/workspace_template/WORKSPACE.tmpl
+ # and tests/ignore_root_user_error/WORKSPACE.
+ # If you update this dependency, please update the tests as well.
maybe(
http_archive,
name = "bazel_skylib",
@@ -42,9 +45,9 @@ def rules_python_internal_deps():
maybe(
http_archive,
name = "rules_testing",
- url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.0.1/rules_testing-v0.0.1.tar.gz",
- sha256 = "47db8fc9c3c1837491333cdcedebf267285479bd709a1ff0a47b19a324817def",
- strip_prefix = "rules_testing-0.0.1",
+ sha256 = "0c2abee201f566a088c720e12bc1d968bc56e6a51b692d9c81b1fe861bdf2be2",
+ strip_prefix = "rules_testing-0.0.5",
+ url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.0.5/rules_testing-v0.0.5.tar.gz",
)
maybe(
diff --git a/python/extensions/BUILD.bazel b/python/extensions/BUILD.bazel
new file mode 100644
index 0000000000..7f6873d581
--- /dev/null
+++ b/python/extensions/BUILD.bazel
@@ -0,0 +1,23 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+ visibility = ["//extensions:__pkg__"],
+)
diff --git a/python/extensions/interpreter.bzl b/python/extensions/interpreter.bzl
new file mode 100644
index 0000000000..b9afe1abda
--- /dev/null
+++ b/python/extensions/interpreter.bzl
@@ -0,0 +1,75 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"Module extension that finds the current toolchain Python binary and creates a symlink to it."
+
+load("@pythons_hub//:interpreters.bzl", "INTERPRETER_LABELS")
+
+def _interpreter_impl(mctx):
+ for mod in mctx.modules:
+ for install_attr in mod.tags.install:
+ _interpreter_repo(
+ name = install_attr.name,
+ python_name = install_attr.python_name,
+ )
+
+interpreter = module_extension(
+ doc = """\
+This extension is used to expose the underlying platform-specific
+interpreter registered as a toolchain. It is used by users to get
+a label to the interpreter for use with pip.parse
+in the MODULES.bazel file.
+""",
+ implementation = _interpreter_impl,
+ tag_classes = {
+ "install": tag_class(
+ attrs = {
+ "name": attr.string(
+ doc = "Name of the interpreter, we use this name to set the interpreter for pip.parse",
+ mandatory = True,
+ ),
+ "python_name": attr.string(
+ doc = "The name set in the previous python.toolchain call.",
+ mandatory = True,
+ ),
+ },
+ ),
+ },
+)
+
+def _interpreter_repo_impl(rctx):
+ rctx.file("BUILD.bazel", "")
+
+ actual_interpreter_label = INTERPRETER_LABELS.get(rctx.attr.python_name)
+ if actual_interpreter_label == None:
+ fail("Unable to find interpreter with name {}".format(rctx.attr.python_name))
+
+ rctx.symlink(actual_interpreter_label, "python")
+
+_interpreter_repo = repository_rule(
+ doc = """\
+Load the INTERPRETER_LABELS map. This map contain of all of the Python binaries
+by name and a label the points to the interpreter binary. The
+binaries are downloaded as part of the python toolchain setup.
+The rule finds the label and creates a symlink named "python" to that
+label. This symlink is then used by pip.
+""",
+ implementation = _interpreter_repo_impl,
+ attrs = {
+ "python_name": attr.string(
+ mandatory = True,
+ doc = "Name of the Python toolchain",
+ ),
+ },
+)
diff --git a/python/extensions.bzl b/python/extensions/pip.bzl
similarity index 64%
rename from python/extensions.bzl
rename to python/extensions/pip.bzl
index 2b0c188554..ce5eea30d4 100644
--- a/python/extensions.bzl
+++ b/python/extensions/pip.bzl
@@ -12,59 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"Module extensions for use with bzlmod"
+"pip module extension for use with bzlmod"
-load("@rules_python//python:repositories.bzl", "python_register_toolchains")
load("@rules_python//python/pip_install:pip_repository.bzl", "locked_requirements_label", "pip_repository_attrs", "pip_repository_bzlmod", "use_isolated", "whl_library")
-load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies")
load("@rules_python//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
-load("@rules_python//python/private:coverage_deps.bzl", "install_coverage_deps")
-
-def _python_impl(module_ctx):
- for mod in module_ctx.modules:
- for attr in mod.tags.toolchain:
- python_register_toolchains(
- name = attr.name,
- python_version = attr.python_version,
- bzlmod = True,
- # Toolchain registration in bzlmod is done in MODULE file
- register_toolchains = False,
- register_coverage_tool = attr.configure_coverage_tool,
- ignore_root_user_error = attr.ignore_root_user_error,
- )
-
-python = module_extension(
- implementation = _python_impl,
- tag_classes = {
- "toolchain": tag_class(
- attrs = {
- "configure_coverage_tool": attr.bool(
- mandatory = False,
- doc = "Whether or not to configure the default coverage tool for the toolchains.",
- ),
- "ignore_root_user_error": attr.bool(
- default = False,
- doc = "Whether the check for root should be ignored or not. This causes cache misses with .pyc files.",
- mandatory = False,
- ),
- "name": attr.string(mandatory = True),
- "python_version": attr.string(mandatory = True),
- },
- ),
- },
-)
-
-# buildifier: disable=unused-variable
-def _internal_deps_impl(module_ctx):
- pip_install_dependencies()
- install_coverage_deps()
-
-internal_deps = module_extension(
- implementation = _internal_deps_impl,
- tag_classes = {
- "install": tag_class(attrs = dict()),
- },
-)
def _pip_impl(module_ctx):
for mod in module_ctx.modules:
@@ -83,6 +34,7 @@ def _pip_impl(module_ctx):
# this does not create the install_deps() macro.
pip_repository_bzlmod(
name = attr.name,
+ repo_name = attr.name,
requirements_lock = attr.requirements_lock,
incompatible_generate_aliases = attr.incompatible_generate_aliases,
)
@@ -122,6 +74,10 @@ def _pip_parse_ext_attrs():
return attrs
pip = module_extension(
+ doc = """\
+This extension is used to create a pip respository and create the various wheel libaries if
+provided in a requirements file.
+""",
implementation = _pip_impl,
tag_classes = {
"parse": tag_class(attrs = _pip_parse_ext_attrs()),
diff --git a/python/extensions/private/BUILD.bazel b/python/extensions/private/BUILD.bazel
new file mode 100644
index 0000000000..f367b71a78
--- /dev/null
+++ b/python/extensions/private/BUILD.bazel
@@ -0,0 +1,23 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:private"])
+
+licenses(["notice"])
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+ visibility = ["//python/extensions/private:__pkg__"],
+)
diff --git a/python/extensions/private/internal_deps.bzl b/python/extensions/private/internal_deps.bzl
new file mode 100644
index 0000000000..dfa3e2682f
--- /dev/null
+++ b/python/extensions/private/internal_deps.bzl
@@ -0,0 +1,25 @@
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"Python toolchain module extension for internal rule use"
+
+load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies")
+load("@rules_python//python/private:coverage_deps.bzl", "install_coverage_deps")
+
+# buildifier: disable=unused-variable
+def _internal_deps_impl(module_ctx):
+ pip_install_dependencies()
+ install_coverage_deps()
+
+internal_deps = module_extension(
+ doc = "This extension to register internal rules_python dependecies.",
+ implementation = _internal_deps_impl,
+ tag_classes = {
+ "install": tag_class(attrs = dict()),
+ },
+)
diff --git a/python/extensions/private/interpreter_hub.bzl b/python/extensions/private/interpreter_hub.bzl
new file mode 100644
index 0000000000..f1ca670cf2
--- /dev/null
+++ b/python/extensions/private/interpreter_hub.bzl
@@ -0,0 +1,58 @@
+# Copyright 2023 The Bazel Authors. All rights reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"Repo rule used by bzlmod extension to create a repo that has a map of Python interpreters and their labels"
+
+load("//python:versions.bzl", "WINDOWS_NAME")
+load("//python/private:toolchains_repo.bzl", "get_host_os_arch", "get_host_platform")
+
+_build_file_for_hub_template = """
+INTERPRETER_LABELS = {{
+{lines}
+}}
+"""
+
+_line_for_hub_template = """\
+ "{name}": Label("@{name}_{platform}//:{path}"),
+"""
+
+def _hub_repo_impl(rctx):
+ (os, arch) = get_host_os_arch(rctx)
+ platform = get_host_platform(os, arch)
+
+ rctx.file("BUILD.bazel", "")
+ is_windows = (os == WINDOWS_NAME)
+ path = "python.exe" if is_windows else "bin/python3"
+
+ lines = "\n".join([_line_for_hub_template.format(
+ name = name,
+ platform = platform,
+ path = path,
+ ) for name in rctx.attr.toolchains])
+
+ rctx.file("interpreters.bzl", _build_file_for_hub_template.format(lines = lines))
+
+hub_repo = repository_rule(
+ doc = """\
+This private rule create a repo with a BUILD file that contains a map of interpreter names
+and the labels to said interpreters. This map is used to by the interpreter hub extension.
+""",
+ implementation = _hub_repo_impl,
+ attrs = {
+ "toolchains": attr.string_list(
+ doc = "List of the base names the toolchain repo defines.",
+ mandatory = True,
+ ),
+ },
+)
diff --git a/python/extensions/python.bzl b/python/extensions/python.bzl
new file mode 100644
index 0000000000..9a3d9ed959
--- /dev/null
+++ b/python/extensions/python.bzl
@@ -0,0 +1,64 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"Python toolchain module extensions for use with bzlmod"
+
+load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+load("@rules_python//python/extensions/private:interpreter_hub.bzl", "hub_repo")
+
+def _python_impl(module_ctx):
+ toolchains = []
+ for mod in module_ctx.modules:
+ for toolchain_attr in mod.tags.toolchain:
+ python_register_toolchains(
+ name = toolchain_attr.name,
+ python_version = toolchain_attr.python_version,
+ bzlmod = True,
+ # Toolchain registration in bzlmod is done in MODULE file
+ register_toolchains = False,
+ register_coverage_tool = toolchain_attr.configure_coverage_tool,
+ ignore_root_user_error = toolchain_attr.ignore_root_user_error,
+ )
+
+ # We collect all of the toolchain names to create
+ # the INTERPRETER_LABELS map. This is used
+ # by interpreter_extensions.bzl
+ toolchains.append(toolchain_attr.name)
+
+ hub_repo(
+ name = "pythons_hub",
+ toolchains = toolchains,
+ )
+
+python = module_extension(
+ doc = "Bzlmod extension that is used to register a Python toolchain.",
+ implementation = _python_impl,
+ tag_classes = {
+ "toolchain": tag_class(
+ attrs = {
+ "configure_coverage_tool": attr.bool(
+ mandatory = False,
+ doc = "Whether or not to configure the default coverage tool for the toolchains.",
+ ),
+ "ignore_root_user_error": attr.bool(
+ default = False,
+ doc = "Whether the check for root should be ignored or not. This causes cache misses with .pyc files.",
+ mandatory = False,
+ ),
+ "name": attr.string(mandatory = True),
+ "python_version": attr.string(mandatory = True),
+ },
+ ),
+ },
+)
diff --git a/python/packaging.bzl b/python/packaging.bzl
index fffd239c15..45d5c963b9 100644
--- a/python/packaging.bzl
+++ b/python/packaging.bzl
@@ -172,6 +172,7 @@ def py_wheel(name, twine = None, **kwargs):
imports = ["."],
main = twine_main,
deps = [twine],
+ visibility = kwargs.get("visibility"),
)
py_wheel_rule = _py_wheel
diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl
index fce0dcdd47..5239fd5f9c 100644
--- a/python/pip_install/pip_repository.bzl
+++ b/python/pip_install/pip_repository.bzl
@@ -128,7 +128,7 @@ def _get_toolchain_unix_cflags(rctx):
er = rctx.execute([
rctx.path(rctx.attr.python_interpreter_target).realpath,
"-c",
- "import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}')",
+ "import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}', end='')",
])
if er.return_code != 0:
fail("could not get python version from interpreter (status {}): {}".format(er.return_code, er.stderr))
@@ -358,7 +358,7 @@ def _pip_repository_bzlmod_impl(rctx):
bzl_packages = sorted([name for name, _ in packages])
- repo_name = rctx.attr.name.split("~")[-1]
+ repo_name = rctx.attr.repo_name
build_contents = _BUILD_FILE_CONTENTS
@@ -367,16 +367,26 @@ def _pip_repository_bzlmod_impl(rctx):
else:
build_contents += _bzlmod_pkg_aliases(repo_name, bzl_packages)
+ # NOTE: we are using the canonical name with the double '@' in order to
+ # always uniquely identify a repository, as the labels are being passed as
+ # a string and the resolution of the label happens at the call-site of the
+ # `requirement`, et al. macros.
+ if rctx.attr.incompatible_generate_aliases:
+ macro_tmpl = "@@{name}//{{}}:{{}}".format(name = rctx.attr.name)
+ else:
+ macro_tmpl = "@@{name}//:{{}}_{{}}".format(name = rctx.attr.name)
+
rctx.file("BUILD.bazel", build_contents)
rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
"%%ALL_REQUIREMENTS%%": _format_repr_list([
- "@{}//{}".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:pkg".format(rctx.attr.name, p)
+ macro_tmpl.format(p, p) if rctx.attr.incompatible_generate_aliases else macro_tmpl.format(p, "pkg")
for p in bzl_packages
]),
"%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
- "@{}//{}:whl".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:whl".format(rctx.attr.name, p)
+ macro_tmpl.format(p, "whl")
for p in bzl_packages
]),
+ "%%MACRO_TMPL%%": macro_tmpl,
"%%NAME%%": rctx.attr.name,
"%%REQUIREMENTS_LOCK%%": str(requirements_txt),
})
@@ -386,6 +396,10 @@ pip_repository_bzlmod_attrs = {
default = False,
doc = "Allow generating aliases in '@pip//:' -> '@pip_//:pkg'. This replaces the aliases generated by the `bzlmod` tooling.",
),
+ "repo_name": attr.string(
+ mandatory = True,
+ doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name",
+ ),
"requirements_darwin": attr.label(
allow_single_file = True,
doc = "Override the requirements_lock attribute when the host platform is Mac OS",
@@ -527,7 +541,7 @@ can be passed.
"isolated": attr.bool(
doc = """\
Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to
-the underlying pip command. Alternatively, the `RULES_PYTHON_PIP_ISOLATED` enviornment varaible can be used
+the underlying pip command. Alternatively, the `RULES_PYTHON_PIP_ISOLATED` environment variable can be used
to control this flag.
""",
default = True,
@@ -550,7 +564,7 @@ of a binary found on the host's `PATH` environment variable. If no value is set
If you are using a custom python interpreter built by another repository rule,
use this attribute to specify its BUILD target. This allows pip_repository to invoke
pip using the same interpreter as your toolchain. If set, takes precedence over
-python_interpreter.
+python_interpreter. An example value: "@python3_x86_64-unknown-linux-gnu//:python".
""",
),
"quiet": attr.bool(
diff --git a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl
index 462829d074..b77bf39c38 100644
--- a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl
+++ b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl
@@ -12,13 +12,20 @@ def _clean_name(name):
return name.replace("-", "_").replace(".", "_").lower()
def requirement(name):
- return "@@%%NAME%%//:" + _clean_name(name) + "_pkg"
+ return "%%MACRO_TMPL%%".format(_clean_name(name), "pkg")
def whl_requirement(name):
- return "@@%%NAME%%//:" + _clean_name(name) + "_whl"
+ return "%%MACRO_TMPL%%".format(_clean_name(name), "whl")
def data_requirement(name):
- return "@@%%NAME%%//:" + _clean_name(name) + "_data"
+ return "%%MACRO_TMPL%%".format(_clean_name(name), "data")
def dist_info_requirement(name):
- return "@@%%NAME%%//:" + _clean_name(name) + "_dist_info"
+ return "%%MACRO_TMPL%%".format(_clean_name(name), "dist_info")
+
+def entry_point(pkg, script = None):
+ """entry_point returns the target of the canonical label of the package entrypoints.
+ """
+ if not script:
+ script = pkg
+ return "@@%%NAME%%_{}//:rules_python_wheel_entry_point_{}".format(_clean_name(pkg), script)
diff --git a/python/pip_install/private/test/requirements_parser_tests.bzl b/python/pip_install/private/test/requirements_parser_tests.bzl
index 13c40c2956..5ea742e70d 100644
--- a/python/pip_install/private/test/requirements_parser_tests.bzl
+++ b/python/pip_install/private/test/requirements_parser_tests.bzl
@@ -62,6 +62,9 @@ SomeProject == 1.3 # This is a comment
FooProject==1.0.0
# Comment
BarProject==2.0.0 #Comment
+""").requirements)
+ asserts.equals(env, [("requests", "requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49")], parse("""\
+requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49
""").requirements)
# Multiline
@@ -71,6 +74,11 @@ certifi==2021.10.8 \
--hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569
# via requests
""").requirements)
+ asserts.equals(env, [("requests", "requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49 --hash=sha256:eca58eb564b134e4ff521a02aa6f566c653835753e1fc8a50a20cb6bee4673cd")], parse("""\
+requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49 \
+ --hash=sha256:eca58eb564b134e4ff521a02aa6f566c653835753e1fc8a50a20cb6bee4673cd
+ # via requirements.txt
+""").requirements)
# Options
asserts.equals(env, ["--pre"], parse("--pre\n").options)
@@ -177,11 +185,11 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r ./requirements.in
+ # via -r requirements.in
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r ./requirements.in
+ # via -r requirements.in
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
@@ -192,7 +200,7 @@ urllib3==1.26.7 \
# via requests
yamllint==1.26.3 \
--hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
- # via -r ./requirements.in
+ # via -r requirements.in
# The following packages are considered to be unsafe in a requirements file:
setuptools==59.6.0 \
diff --git a/python/pip_install/requirements.bzl b/python/pip_install/requirements.bzl
index dd38c9df5b..7594471897 100644
--- a/python/pip_install/requirements.bzl
+++ b/python/pip_install/requirements.bzl
@@ -75,7 +75,7 @@ def compile_pip_requirements(
# where it appears, which is to say, in @rules_python
pip_compile = Label("//python/pip_install/tools/dependency_resolver:dependency_resolver.py")
- loc = "$(rootpath {})"
+ loc = "$(rlocationpath {})"
args = [
loc.format(requirements_in),
@@ -99,6 +99,7 @@ def compile_pip_requirements(
requirement("importlib_metadata"),
requirement("zipp"),
requirement("more_itertools"),
+ Label("//python/runfiles:runfiles"),
] + extra_deps
tags = tags or []
diff --git a/python/pip_install/requirements_parser.bzl b/python/pip_install/requirements_parser.bzl
index ac90b95328..3b49fdf181 100644
--- a/python/pip_install/requirements_parser.bzl
+++ b/python/pip_install/requirements_parser.bzl
@@ -116,7 +116,7 @@ def _handleParseOption(input, buffer, result):
elif input == "\n" or input == EOF:
result.options.append(buffer.rstrip("\n"))
return (_STATE.ConsumeSpace, "")
- elif input == "#":
+ elif input == "#" and (len(buffer) == 0 or buffer[-1].isspace()):
return (_STATE.ConsumeComment, buffer)
return (_STATE.ParseOption, buffer + input)
@@ -127,7 +127,7 @@ def _handleParseRequirement(input, buffer, result):
elif input == "\n" or input == EOF:
result.requirements[-1] = (result.requirements[-1][0], buffer.rstrip(" \n"))
return (_STATE.ConsumeSpace, "")
- elif input == "#":
+ elif input == "#" and (len(buffer) == 0 or buffer[-1].isspace()):
return (_STATE.ConsumeComment, buffer)
return (_STATE.ParseRequirement, buffer + input)
diff --git a/python/pip_install/tools/dependency_resolver/dependency_resolver.py b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
index e636febd93..89e355806c 100644
--- a/python/pip_install/tools/dependency_resolver/dependency_resolver.py
+++ b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
@@ -23,6 +23,8 @@
import piptools.writer as piptools_writer
from piptools.scripts.compile import cli
+from python.runfiles import runfiles
+
# Replace the os.replace function with shutil.copy to work around os.replace not being able to
# replace or move files across filesystems.
os.replace = shutil.copy
@@ -66,6 +68,15 @@ def _select_golden_requirements_file(
return requirements_txt
+def _locate(bazel_runfiles, file):
+ """Look up the file via Rlocation"""
+
+ if not file:
+ return file
+
+ return bazel_runfiles.Rlocation(file)
+
+
if __name__ == "__main__":
if len(sys.argv) < 4:
print(
@@ -75,6 +86,7 @@ def _select_golden_requirements_file(
sys.exit(1)
parse_str_none = lambda s: None if s == "None" else s
+ bazel_runfiles = runfiles.Create()
requirements_in = sys.argv.pop(1)
requirements_txt = sys.argv.pop(1)
@@ -83,10 +95,25 @@ def _select_golden_requirements_file(
requirements_windows = parse_str_none(sys.argv.pop(1))
update_target_label = sys.argv.pop(1)
- # The requirements_in file could be generated, so we will need to remove the
- # absolute prefixes in the locked requirements output file.
- requirements_in_path = Path(requirements_in)
- resolved_requirements_in = str(requirements_in_path.resolve())
+ resolved_requirements_in = _locate(bazel_runfiles, requirements_in)
+ resolved_requirements_txt = _locate(bazel_runfiles, requirements_txt)
+
+ # Files in the runfiles directory has the following naming schema:
+ # Main repo: __main__/
+ # External repo: /
+ # We want to strip both __main__ and from the absolute prefix
+ # to keep the requirements lock file agnostic.
+ repository_prefix = requirements_txt[: requirements_txt.index("/") + 1]
+ absolute_path_prefix = resolved_requirements_txt[
+ : -(len(requirements_txt) - len(repository_prefix))
+ ]
+
+ # As requirements_in might contain references to generated files we want to
+ # use the runfiles file first. Thus, we need to compute the relative path
+ # from the execution root.
+ # Note: Windows cannot reference generated files without runfiles support enabled.
+ requirements_in_relative = requirements_in[len(repository_prefix) :]
+ requirements_txt_relative = requirements_txt[len(repository_prefix) :]
# Before loading click, set the locale for its parser.
# If it leaks through to the system setting, it may fail:
@@ -112,7 +139,7 @@ def _select_golden_requirements_file(
)
# Those two files won't necessarily be on the same filesystem, so we can't use os.replace
# or shutil.copyfile, as they will fail with OSError: [Errno 18] Invalid cross-device link.
- shutil.copy(requirements_txt, requirements_out)
+ shutil.copy(resolved_requirements_txt, requirements_out)
update_command = os.getenv("CUSTOM_COMPILE_COMMAND") or "bazel run %s" % (
update_target_label,
@@ -123,24 +150,33 @@ def _select_golden_requirements_file(
sys.argv.append("--generate-hashes")
sys.argv.append("--output-file")
- sys.argv.append(requirements_txt if UPDATE else requirements_out)
+ sys.argv.append(requirements_txt_relative if UPDATE else requirements_out)
sys.argv.append(
- requirements_in if requirements_in_path.exists() else resolved_requirements_in
+ requirements_in_relative
+ if Path(requirements_in_relative).exists()
+ else resolved_requirements_in
)
+ print(sys.argv)
if UPDATE:
- print("Updating " + requirements_txt)
+ print("Updating " + requirements_txt_relative)
if "BUILD_WORKSPACE_DIRECTORY" in os.environ:
workspace = os.environ["BUILD_WORKSPACE_DIRECTORY"]
- requirements_txt_tree = os.path.join(workspace, requirements_txt)
+ requirements_txt_tree = os.path.join(workspace, requirements_txt_relative)
# In most cases, requirements_txt will be a symlink to the real file in the source tree.
# If symlinks are not enabled (e.g. on Windows), then requirements_txt will be a copy,
# and we should copy the updated requirements back to the source tree.
- if not os.path.samefile(requirements_txt, requirements_txt_tree):
+ if not os.path.samefile(resolved_requirements_txt, requirements_txt_tree):
atexit.register(
- lambda: shutil.copy(requirements_txt, requirements_txt_tree)
+ lambda: shutil.copy(
+ resolved_requirements_txt, requirements_txt_tree
+ )
)
cli()
+ requirements_txt_relative_path = Path(requirements_txt_relative)
+ content = requirements_txt_relative_path.read_text()
+ content = content.replace(absolute_path_prefix, "")
+ requirements_txt_relative_path.write_text(content)
else:
# cli will exit(0) on success
try:
@@ -153,7 +189,7 @@ def _select_golden_requirements_file(
print(
"pip-compile exited with code 2. This means that pip-compile found "
"incompatible requirements or could not find a version that matches "
- f"the install requirement in {requirements_in}.",
+ f"the install requirement in {requirements_in_relative}.",
file=sys.stderr,
)
sys.exit(1)
@@ -164,8 +200,9 @@ def _select_golden_requirements_file(
requirements_darwin,
requirements_windows,
)
- golden = open(golden_filename).readlines()
+ golden = open(_locate(bazel_runfiles, golden_filename)).readlines()
out = open(requirements_out).readlines()
+ out = [line.replace(absolute_path_prefix, "") for line in out]
if golden != out:
import difflib
diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel
index 4068ea480b..f454f42cf3 100644
--- a/python/private/BUILD.bazel
+++ b/python/private/BUILD.bazel
@@ -44,7 +44,11 @@ bzl_library(
bzl_library(
name = "util_bzl",
srcs = ["util.bzl"],
- visibility = ["//python:__subpackages__"],
+ visibility = [
+ "//docs:__subpackages__",
+ "//python:__subpackages__",
+ ],
+ deps = ["@bazel_skylib//lib:types"],
)
# @bazel_tools can't define bzl_library itself, so we just put a wrapper around it.
diff --git a/python/private/util.bzl b/python/private/util.bzl
index 25a50aac6a..f0d43737a0 100644
--- a/python/private/util.bzl
+++ b/python/private/util.bzl
@@ -1,5 +1,7 @@
"""Functionality shared by multiple pieces of code."""
+load("@bazel_skylib//lib:types.bzl", "types")
+
def copy_propagating_kwargs(from_kwargs, into_kwargs = None):
"""Copies args that must be compatible between two targets with a dependency relationship.
@@ -36,8 +38,23 @@ def copy_propagating_kwargs(from_kwargs, into_kwargs = None):
_MIGRATION_TAG = "__PYTHON_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__"
def add_migration_tag(attrs):
+ """Add a special tag to `attrs` to aid migration off native rles.
+
+ Args:
+ attrs: dict of keyword args. The `tags` key will be modified in-place.
+
+ Returns:
+ The same `attrs` object, but modified.
+ """
if "tags" in attrs and attrs["tags"] != None:
- attrs["tags"] = attrs["tags"] + [_MIGRATION_TAG]
+ tags = attrs["tags"]
+
+ # Preserve the input type: this allows a test verifying the underlying
+ # rule can accept the tuple for the tags argument.
+ if types.is_tuple(tags):
+ attrs["tags"] = tags + (_MIGRATION_TAG,)
+ else:
+ attrs["tags"] = tags + [_MIGRATION_TAG]
else:
attrs["tags"] = [_MIGRATION_TAG]
return attrs
diff --git a/python/repositories.bzl b/python/repositories.bzl
index 2429d7e026..358df4341b 100644
--- a/python/repositories.bzl
+++ b/python/repositories.bzl
@@ -106,11 +106,11 @@ def _python_repository_impl(rctx):
python_version = rctx.attr.python_version
python_short_version = python_version.rpartition(".")[0]
release_filename = rctx.attr.release_filename
- url = rctx.attr.urls or [rctx.attr.url]
+ urls = rctx.attr.urls or [rctx.attr.url]
if release_filename.endswith(".zst"):
rctx.download(
- url = url,
+ url = urls,
sha256 = rctx.attr.sha256,
output = release_filename,
)
@@ -153,7 +153,7 @@ def _python_repository_impl(rctx):
fail(fail_msg)
else:
rctx.download_and_extract(
- url = url,
+ url = urls,
sha256 = rctx.attr.sha256,
stripPrefix = rctx.attr.strip_prefix,
)
@@ -348,7 +348,7 @@ py_runtime_pair(
rctx.file(STANDALONE_INTERPRETER_FILENAME, "# File intentionally left blank. Indicates that this is an interpreter repo created by rules_python.")
rctx.file("BUILD.bazel", build_content)
- return {
+ attrs = {
"coverage_tool": rctx.attr.coverage_tool,
"distutils": rctx.attr.distutils,
"distutils_content": rctx.attr.distutils_content,
@@ -360,9 +360,15 @@ py_runtime_pair(
"release_filename": release_filename,
"sha256": rctx.attr.sha256,
"strip_prefix": rctx.attr.strip_prefix,
- "url": url,
}
+ if rctx.attr.url:
+ attrs["url"] = rctx.attr.url
+ else:
+ attrs["urls"] = urls
+
+ return attrs
+
python_repository = repository_rule(
_python_repository_impl,
doc = "Fetches the external tools needed for the Python toolchain.",
diff --git a/python/tests/toolchains/workspace_template/WORKSPACE.tmpl b/python/tests/toolchains/workspace_template/WORKSPACE.tmpl
index d0aa700928..973e020c1e 100644
--- a/python/tests/toolchains/workspace_template/WORKSPACE.tmpl
+++ b/python/tests/toolchains/workspace_template/WORKSPACE.tmpl
@@ -25,3 +25,15 @@ python_register_toolchains(
name = "python",
python_version = "%python_version%",
)
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+ name = "bazel_skylib",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
+ ],
+ sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d",
+)
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+bazel_skylib_workspace()
diff --git a/python/versions.bzl b/python/versions.bzl
index 662f89d04b..baf6e33a06 100644
--- a/python/versions.bzl
+++ b/python/versions.bzl
@@ -86,6 +86,17 @@ TOOL_VERSIONS = {
},
"strip_prefix": "python",
},
+ "3.8.16": {
+ "url": "20230116/cpython-{python_version}+20230116-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "d1f408569d8807c1053939d7822b082a17545e363697e1ce3cfb1ee75834c7be",
+ "aarch64-unknown-linux-gnu": "15d00bc8400ed6d94c665a797dc8ed7a491ae25c5022e738dcd665cd29beec42",
+ "x86_64-apple-darwin": "484ba901f64fc7888bec5994eb49343dc3f9d00ed43df17ee9c40935aad4aa18",
+ "x86_64-pc-windows-msvc": "b446bec833eaba1bac9063bb9b4aeadfdf67fa81783b4487a90c56d408fb7994",
+ "x86_64-unknown-linux-gnu": "c890de112f1ae31283a31fefd2061d5c97bdd4d1bdd795552c7abddef2697ea1",
+ },
+ "strip_prefix": "python",
+ },
"3.9.10": {
"url": "20220227/cpython-{python_version}+20220227-{platform}-{build}.tar.gz",
"sha256": {
diff --git a/tests/compile_pip_requirements/requirements_lock.txt b/tests/compile_pip_requirements/requirements_lock.txt
index 8f7037ce7a..4ca4a11f3e 100644
--- a/tests/compile_pip_requirements/requirements_lock.txt
+++ b/tests/compile_pip_requirements/requirements_lock.txt
@@ -7,8 +7,8 @@
pip==22.3.1 \
--hash=sha256:65fd48317359f3af8e593943e6ae1506b66325085ea64b706a998c6e83eeaf38 \
--hash=sha256:908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077
- # via -r ./requirements.in
+ # via -r requirements.in
setuptools==65.6.3 \
--hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
--hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
- # via -r ./requirements_extra.in
+ # via -r requirements_extra.in
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/.bazelrc b/tests/compile_pip_requirements_test_from_external_workspace/.bazelrc
new file mode 100644
index 0000000000..b98fc09774
--- /dev/null
+++ b/tests/compile_pip_requirements_test_from_external_workspace/.bazelrc
@@ -0,0 +1 @@
+test --test_output=errors
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/.gitignore b/tests/compile_pip_requirements_test_from_external_workspace/.gitignore
new file mode 100644
index 0000000000..ac51a054d2
--- /dev/null
+++ b/tests/compile_pip_requirements_test_from_external_workspace/.gitignore
@@ -0,0 +1 @@
+bazel-*
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/BUILD.bazel b/tests/compile_pip_requirements_test_from_external_workspace/BUILD.bazel
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/README.md b/tests/compile_pip_requirements_test_from_external_workspace/README.md
new file mode 100644
index 0000000000..8ce77ca1f1
--- /dev/null
+++ b/tests/compile_pip_requirements_test_from_external_workspace/README.md
@@ -0,0 +1,3 @@
+# compile_pip_requirements_test_from_external_workspace
+
+This test checks that compile_pip_requirements test can be run from external workspaces without invalidating the lock file.
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/WORKSPACE b/tests/compile_pip_requirements_test_from_external_workspace/WORKSPACE
new file mode 100644
index 0000000000..35686a1d30
--- /dev/null
+++ b/tests/compile_pip_requirements_test_from_external_workspace/WORKSPACE
@@ -0,0 +1,36 @@
+local_repository(
+ name = "rules_python",
+ path = "../..",
+)
+
+load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
+
+py_repositories()
+
+load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies")
+
+pip_install_dependencies()
+
+python_register_toolchains(
+ name = "python39",
+ python_version = "3.9",
+)
+
+load("@python39//:defs.bzl", "interpreter")
+load("@rules_python//python:pip.bzl", "pip_parse")
+
+local_repository(
+ name = "external_repository",
+ path = "../compile_pip_requirements",
+)
+
+pip_parse(
+ name = "pypi",
+ python_interpreter_target = interpreter,
+ requirements_lock = "@external_repository//:requirements_lock.txt",
+)
+
+load("@pypi//:requirements.bzl", "install_deps")
+
+# Initialize repositories for all packages in requirements_lock.txt.
+install_deps()
diff --git a/tests/ignore_root_user_error/WORKSPACE b/tests/ignore_root_user_error/WORKSPACE
index d2f4d6ec3a..e0528e4047 100644
--- a/tests/ignore_root_user_error/WORKSPACE
+++ b/tests/ignore_root_user_error/WORKSPACE
@@ -10,3 +10,18 @@ python_register_toolchains(
ignore_root_user_error = True,
python_version = "3.9",
)
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "bazel_skylib",
+ sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
+ ],
+)
+
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+
+bazel_skylib_workspace()
diff --git a/tests/pip_repository_entry_points/requirements.txt b/tests/pip_repository_entry_points/requirements.txt
index 90b717e7a7..a93facc03b 100644
--- a/tests/pip_repository_entry_points/requirements.txt
+++ b/tests/pip_repository_entry_points/requirements.txt
@@ -170,7 +170,7 @@ setuptools==59.6.0 \
--hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
--hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
# via
- # -r ./requirements.in
+ # -r requirements.in
# sphinx
# yamllint
snowballstemmer==2.2.0 \
@@ -180,7 +180,7 @@ snowballstemmer==2.2.0 \
sphinx==4.3.2 \
--hash=sha256:0a8836751a68306b3fe97ecbe44db786f8479c3bf4b80e3a7f5c838657b4698c \
--hash=sha256:6a11ea5dd0bdb197f9c2abc2e0ce73e01340464feaece525e64036546d24c851
- # via -r ./requirements.in
+ # via -r requirements.in
sphinxcontrib-applehelp==1.0.2 \
--hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a \
--hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58
@@ -212,4 +212,4 @@ urllib3==1.26.7 \
yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/tests/pip_repository_entry_points/requirements_windows.txt b/tests/pip_repository_entry_points/requirements_windows.txt
index 14c3dc3274..651e2b5e56 100644
--- a/tests/pip_repository_entry_points/requirements_windows.txt
+++ b/tests/pip_repository_entry_points/requirements_windows.txt
@@ -174,7 +174,7 @@ setuptools==59.6.0 \
--hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
--hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
# via
- # -r ./requirements.in
+ # -r requirements.in
# sphinx
# yamllint
snowballstemmer==2.2.0 \
@@ -184,7 +184,7 @@ snowballstemmer==2.2.0 \
sphinx==4.3.2 \
--hash=sha256:0a8836751a68306b3fe97ecbe44db786f8479c3bf4b80e3a7f5c838657b4698c \
--hash=sha256:6a11ea5dd0bdb197f9c2abc2e0ce73e01340464feaece525e64036546d24c851
- # via -r ./requirements.in
+ # via -r requirements.in
sphinxcontrib-applehelp==1.0.2 \
--hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a \
--hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58
@@ -216,4 +216,4 @@ urllib3==1.26.7 \
yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
- # via -r ./requirements.in
+ # via -r requirements.in
diff --git a/tools/bazel_integration_test/test_runner.py b/tools/bazel_integration_test/test_runner.py
index 03599fbd0e..3940e87c37 100644
--- a/tools/bazel_integration_test/test_runner.py
+++ b/tools/bazel_integration_test/test_runner.py
@@ -79,6 +79,7 @@ def main(conf_file):
"--override_module=rules_python=%s/rules_python"
% os.environ["TEST_SRCDIR"]
)
+ bazel_args.append("--enable_bzlmod")
# Bazel's wrapper script needs this or you get
# 2020/07/13 21:58:11 could not get the user's cache directory: $HOME is not defined
diff --git a/tools/bazel_integration_test/update_deleted_packages.sh b/tools/bazel_integration_test/update_deleted_packages.sh
index ce7b05ada7..54db02630f 100755
--- a/tools/bazel_integration_test/update_deleted_packages.sh
+++ b/tools/bazel_integration_test/update_deleted_packages.sh
@@ -15,11 +15,25 @@
# For integration tests, we want to be able to glob() up the sources inside a nested package
# See explanation in .bazelrc
+#
+# This script ensures that we only delete subtrees that have something a file
+# signifying a new bazel workspace, whether it be bzlmod or classic. Generic
+# algorithm:
+# 1. Get all directories where a WORKSPACE or MODULE.bazel exists.
+# 2. For each of the directories, get all directories that contains a BUILD.bazel file.
+# 3. Sort and remove duplicates.
-set -eux
+set -euxo pipefail
DIR="$(dirname $0)/../.."
+cd $DIR
+
# The sed -i.bak pattern is compatible between macos and linux
sed -i.bak "/^[^#].*--deleted_packages/s#=.*#=$(\
- find examples/*/* tests/*/* \( -name BUILD -or -name BUILD.bazel \) | xargs -n 1 dirname | paste -sd, -\
+ find examples/*/* tests/*/* \( -name WORKSPACE -or -name MODULE.bazel \) |
+ xargs -n 1 dirname |
+ xargs -n 1 -I{} find {} \( -name BUILD -or -name BUILD.bazel \) |
+ xargs -n 1 dirname |
+ sort -u |
+ paste -sd, -\
)#" $DIR/.bazelrc && rm .bazelrc.bak
diff --git a/tools/build_defs/python/tests/base_tests.bzl b/tools/build_defs/python/tests/base_tests.bzl
index 715aea7fde..467611fcd8 100644
--- a/tools/build_defs/python/tests/base_tests.bzl
+++ b/tools/build_defs/python/tests/base_tests.bzl
@@ -15,7 +15,7 @@
load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
load("@rules_testing//lib:truth.bzl", "matching")
-load("@rules_testing//lib:util.bzl", rt_util = "util")
+load("@rules_testing//lib:util.bzl", "PREVENT_IMPLICIT_BUILDING_TAGS", rt_util = "util")
load("//python:defs.bzl", "PyInfo")
load("//tools/build_defs/python/tests:py_info_subject.bzl", "py_info_subject")
load("//tools/build_defs/python/tests:util.bzl", pt_util = "util")
@@ -99,5 +99,26 @@ def _test_data_sets_uses_shared_library_impl(env, target):
_tests.append(_test_data_sets_uses_shared_library)
+def _test_tags_can_be_tuple(name, config):
+ # We don't use a helper because we want to ensure that value passed is
+ # a tuple.
+ config.base_test_rule(
+ name = name + "_subject",
+ tags = ("one", "two") + tuple(PREVENT_IMPLICIT_BUILDING_TAGS),
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_tags_can_be_tuple_impl,
+ )
+
+def _test_tags_can_be_tuple_impl(env, target):
+ env.expect.that_target(target).tags().contains_at_least([
+ "one",
+ "two",
+ ])
+
+_tests.append(_test_tags_can_be_tuple)
+
def create_base_tests(config):
return pt_util.create_tests(_tests, config = config)
diff --git a/tools/build_defs/python/tests/py_test/py_test_tests.bzl b/tools/build_defs/python/tests/py_test/py_test_tests.bzl
index f2b4875b15..8bb2fc2af0 100644
--- a/tools/build_defs/python/tests/py_test/py_test_tests.bzl
+++ b/tools/build_defs/python/tests/py_test/py_test_tests.bzl
@@ -22,6 +22,12 @@ load(
)
load("//tools/build_defs/python/tests:util.bzl", pt_util = "util")
+# Explicit Label() calls are required so that it resolves in @rules_python context instead of
+# @rules_testing context.
+_FAKE_CC_TOOLCHAIN = Label("//tools/build_defs/python/tests:cc_toolchain_suite")
+_PLATFORM_MAC = Label("//tools/build_defs/python/tests:mac")
+_PLATFORM_LINUX = Label("//tools/build_defs/python/tests:linux")
+
_tests = []
def _test_mac_requires_darwin_for_execution(name, config):
@@ -44,8 +50,8 @@ def _test_mac_requires_darwin_for_execution(name, config):
target = name + "_subject",
config_settings = {
"//command_line_option:cpu": "darwin_x86_64",
- "//command_line_option:crosstool_top": "@rules_python//tools/build_defs/python/tests:cc_toolchain_suite",
- #"//command_line_option:platforms": "@rules_python//tools/build_defs/python/tests:mac",
+ "//command_line_option:crosstool_top": _FAKE_CC_TOOLCHAIN,
+ "//command_line_option:platforms": [_PLATFORM_MAC],
},
)
@@ -75,8 +81,8 @@ def _test_non_mac_doesnt_require_darwin_for_execution(name, config):
target = name + "_subject",
config_settings = {
"//command_line_option:cpu": "k8",
- "//command_line_option:crosstool_top": "@rules_python//tools/build_defs/python/tests:cc_toolchain_suite",
- #"//command_line_option:platforms": "@rules_python//tools/build_defs/python/tests:linux",
+ "//command_line_option:crosstool_top": _FAKE_CC_TOOLCHAIN,
+ "//command_line_option:platforms": [_PLATFORM_LINUX],
},
)