From 73aec8f29b12b1e0f69f2cb7fc8e7fa2c34ca591 Mon Sep 17 00:00:00 2001 From: Ivo List Date: Mon, 24 Apr 2023 17:59:34 +0200 Subject: [PATCH 01/32] fix: remove reference to @bazel_tools//tools/python/private:defs.bzl (#1173) The file was removed in Bazel@HEAD in https://github.com/bazelbuild/bazel/pull/17545 This fixes failures when using rules_python with Bazel@HEAD. Addresses: https://github.com/bazelbuild/bazel/issues/17874 --- docs/BUILD.bazel | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index e1163d9d0e..27af3e7ed5 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", ], From c5f24dd4927a0ce9881792389c84e359a3a7b528 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Mon, 24 Apr 2023 22:10:42 -0700 Subject: [PATCH 02/32] docs: Tell how to use GitHub to find commits in an upcoming release. (#1092) I can never remember what the syntax is of the compare URLs, so just doc it to make it easier. --- DEVELOPING.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/DEVELOPING.md b/DEVELOPING.md index 092e3efeaf..2972d96b79 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -7,17 +7,24 @@ Start from a clean checkout at `main`. Before running through the release it's good to run the build and the tests locally, and make sure CI is passing. You can also test-drive the commit in an existing Bazel workspace to sanity check functionality. +#### Steps +1. [Determine the next semantic version number](#determining-semantic-version) +1. Create a tag and push, e.g. `git tag 0.5.0 upstream/main && git push upstream --tags` + NOTE: Pushing the tag will trigger release automation. +1. Watch the release automation run on https://github.com/bazelbuild/rules_python/actions +1. Add missing information to the release notes. The automatic release note + generation only includes commits associated with issues. + #### Determining Semantic Version **rules_python** is currently using [Zero-based versioning](https://0ver.org/) and thus backwards-incompatible API changes still come under the minor-version digit. So releases with API changes and new features bump the minor, and -those with only bug fixes and other minor changes bump the patch digit. +those with only bug fixes and other minor changes bump the patch digit. + +To find if there were any features added or incompatible changes made, review +the commit history. This can be done using github by going to the url: +`https://github.com/bazelbuild/rules_python/compare/...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. From 952880642e157cc1dadba82579e7b18dde9b9160 Mon Sep 17 00:00:00 2001 From: Rasrack Date: Tue, 25 Apr 2023 19:20:00 +0200 Subject: [PATCH 03/32] fix: compile_pip_requirements test from external repositories (#1124) Previously when running the compile_pip_requirements test from an external repository the test failed. This was due to the fact that paths in the annotations of the lock file contained paths from the external repository. Another problem was that the requirement files could not be located. --- .bazelci/presubmit.yml | 38 +++++++++++ .../build_file_generation/gazelle_python.yaml | 2 +- .../requirements_lock.txt | 2 +- .../requirements_windows.txt | 2 +- examples/bzlmod/requirements_lock.txt | 12 ++-- examples/bzlmod/requirements_windows.txt | 12 ++-- examples/pip_install/requirements.txt | 8 +-- examples/pip_install/requirements_windows.txt | 6 +- examples/pip_parse/requirements_lock.txt | 6 +- examples/pip_parse_vendored/requirements.txt | 2 +- .../requirements.txt | 4 +- .../test/requirements_parser_tests.bzl | 6 +- python/pip_install/requirements.bzl | 3 +- .../dependency_resolver.py | 63 +++++++++++++++---- .../requirements_lock.txt | 4 +- .../.bazelrc | 1 + .../.gitignore | 1 + .../BUILD.bazel | 0 .../README.md | 3 + .../WORKSPACE | 36 +++++++++++ .../requirements.txt | 6 +- .../requirements_windows.txt | 6 +- 22 files changed, 170 insertions(+), 53 deletions(-) create mode 100644 tests/compile_pip_requirements_test_from_external_workspace/.bazelrc create mode 100644 tests/compile_pip_requirements_test_from_external_workspace/.gitignore create mode 100644 tests/compile_pip_requirements_test_from_external_workspace/BUILD.bazel create mode 100644 tests/compile_pip_requirements_test_from_external_workspace/README.md create mode 100644 tests/compile_pip_requirements_test_from_external_workspace/WORKSPACE diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 0e9feab093..7b5ba8b2f2 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -509,3 +509,41 @@ tasks: name: ignore_root_user_error integration tests on Windows working_directory: tests/ignore_root_user_error platform: windows + + integration_compile_pip_requirements_test_from_external_repo_ubuntu_min: + <<: *minimum_supported_version + name: compile_pip_requirements test from external repo on Ubuntu using minimum supported Bazel version + working_directory: tests/compile_pip_requirements_test_from_external_workspace + platform: ubuntu2004 + shell_commands: + # Assert that @external_repository//:requirements_test does the right thing. + - "bazel test @external_repository//..." + integration_compile_pip_requirements_test_from_external_repo_ubuntu: + name: compile_pip_requirements test from external repo on Ubuntu + working_directory: tests/compile_pip_requirements_test_from_external_workspace + platform: ubuntu2004 + shell_commands: + # Assert that @external_repository//:requirements_test does the right thing. + - "bazel test @external_repository//..." + integration_compile_pip_requirements_test_from_external_repo_debian: + name: compile_pip_requirements test from external repo on Debian + working_directory: tests/compile_pip_requirements_test_from_external_workspace + platform: debian11 + shell_commands: + # Assert that @external_repository//:requirements_test does the right thing. + - "bazel test @external_repository//..." + integration_compile_pip_requirements_test_from_external_repo_macos: + name: compile_pip_requirements test from external repo on macOS + working_directory: tests/compile_pip_requirements_test_from_external_workspace + platform: macos + shell_commands: + # Assert that @external_repository//:requirements_test does the right thing. + - "bazel test @external_repository//..." + integration_compile_pip_requirements_test_from_external_repo_windows: + name: compile_pip_requirements test from external repo on Windows + working_directory: tests/compile_pip_requirements_test_from_external_workspace + platform: windows + shell_commands: + # Assert that @external_repository//:requirements_test does the right thing. + - "bazel test @external_repository//..." + 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/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/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/python/pip_install/private/test/requirements_parser_tests.bzl b/python/pip_install/private/test/requirements_parser_tests.bzl index 13c40c2956..c13ec204fb 100644 --- a/python/pip_install/private/test/requirements_parser_tests.bzl +++ b/python/pip_install/private/test/requirements_parser_tests.bzl @@ -177,11 +177,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 +192,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/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/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/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 From ba2a903bc1e608c5847bb0b51fd60709b0a187f3 Mon Sep 17 00:00:00 2001 From: Mingliang Jiang Date: Tue, 25 Apr 2023 16:39:51 -0700 Subject: [PATCH 04/32] feat: add Python 3.8.16 (#1168) Add python 3.8.16 --- python/versions.bzl | 11 +++++++++++ 1 file changed, 11 insertions(+) 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": { From fb6f49f76db31273aa74f86e6ba50bc4facdc24f Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Tue, 25 Apr 2023 20:09:45 -0700 Subject: [PATCH 05/32] test: Set mac platform for test_mac_requires_darwin_for_execution (#1179) This makes the test pass on Bazel built from head. The failure appears due to not forcing the test to a Mac platform, so the underlying logic in `py_test` to detect the Mac platform fails and doesn't add the ExecutionInfo with the necessary info. Work towards bazelbuild/bazel/issues/18170 --- tools/build_defs/python/tests/py_test/py_test_tests.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..41fd27da55 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 @@ -45,7 +45,7 @@ def _test_mac_requires_darwin_for_execution(name, config): 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:platforms": "@rules_python//tools/build_defs/python/tests:mac", }, ) From 600dbe1d10d7055a3fb0644e0cec5badbd5dd240 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Tue, 25 Apr 2023 20:10:02 -0700 Subject: [PATCH 06/32] fix: Don't reference deleted private bazel_tools bzl file (#1180) The latest versions of Bazel have removed the `@bazel_tools//tools/python:private/defs.bzl` file, so it can no longer be referenced. Work towards bazelbuild/bazel/issues/18170 --- BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel index dff608a1ca..35a3df892f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -52,7 +52,6 @@ filegroup( "//python/pip_install:bzl", "//python:bzl", # Requires Bazel 0.29 onward for public visibility of these .bzl files. - "@bazel_tools//tools/python:private/defs.bzl", "@bazel_tools//tools/python:python_version.bzl", "@bazel_tools//tools/python:srcs_version.bzl", "@bazel_tools//tools/python:toolchain.bzl", From 2882bb6eb39b974fc8ba8869ce0f0787598cc69a Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Thu, 27 Apr 2023 17:14:51 +0100 Subject: [PATCH 07/32] docs: Add starlark directive to code snippet (#1170) A very minor cleaup change. --- gazelle/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gazelle/README.md b/gazelle/README.md index e9a8052353..2cd38764fc 100644 --- a/gazelle/README.md +++ b/gazelle/README.md @@ -93,7 +93,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") From 548ced53f980d726f9d8996572fa791f7c8ce0cc Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Thu, 27 Apr 2023 14:04:39 -0700 Subject: [PATCH 08/32] tests: Upgrade rules_testing to 0.0.5 (#1184) This just keeps it at a recent version, which makes errors easier to grok. rules_testing recently underwent a large refactor, so it's confusing when errors reference lines that no longer exist in recent versions. --- internal_deps.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal_deps.bzl b/internal_deps.bzl index 8f52b0e7d7..86a53b25e7 100644 --- a/internal_deps.bzl +++ b/internal_deps.bzl @@ -42,9 +42,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( From ce749147a9a4f8fc8ef6141bf34ab538ed7f7476 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Fri, 28 Apr 2023 09:21:40 -0700 Subject: [PATCH 09/32] tests: Set linux platform for test_non_mac_doesnt_require_darwin_for_execution (#1183) This is the inverse test of the one testing for the mac platform. As before, the line forcing the platform to a non-mac platform was commented out, which meant, when a mac host built it, it would build the underlying target for Mac, which violated the test's assumptions. Work towards bazelbuild/bazel/issues/18170 Fixes #1185 --- tools/build_defs/python/tests/py_test/py_test_tests.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 41fd27da55..560883200a 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 @@ -76,7 +76,7 @@ def _test_non_mac_doesnt_require_darwin_for_execution(name, config): 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:platforms": "@rules_python//tools/build_defs/python/tests:linux", }, ) From 1d1efe906b4c5bf215f807844ba9b53869fa53e6 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Tue, 2 May 2023 02:34:57 +0900 Subject: [PATCH 10/32] fix(bzlmod): correctly template repository macros for requirements, etc (#1190) It seems that the macros for specifying the requirements break when the user starts using `incompatible_generate_aliases=True`. This PR fixes this. Testing done: 1. Modify the example: ``` $ git diff diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel index ce91228..1750210 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -26,6 +26,7 @@ register_toolchains( pip = use_extension("@rules_python//python:extensions.bzl", "pip") pip.parse( name = "pip", + incompatible_generate_aliases=True, requirements_lock = "//:requirements_lock.txt", requirements_windows = "//:requirements_windows.txt", ) ``` 2. Run `bazel build ...` and check that it is still working. I noticed this when working on #1189 and creating a separate PR for easier cherry-picking if we wanted to make a patch release which includes this. I am not sure how I could make an automated test for this other than creating a separate example. --- python/pip_install/pip_repository.bzl | 11 ++++++++++- .../pip_repository_requirements_bzlmod.bzl.tmpl | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index fce0dcdd47..1ea7bca88a 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -367,6 +367,15 @@ 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([ @@ -377,7 +386,7 @@ def _pip_repository_bzlmod_impl(rctx): "@{}//{}:whl".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:whl".format(rctx.attr.name, p) for p in bzl_packages ]), - "%%NAME%%": rctx.attr.name, + "%%MACRO_TMPL%%": macro_tmpl, "%%REQUIREMENTS_LOCK%%": str(requirements_txt), }) diff --git a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl index 462829d074..1b2e2178bb 100644 --- a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl +++ b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl @@ -12,13 +12,13 @@ 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") From c20aa1a3f5756a3860d6f6b595464edbf7964ea4 Mon Sep 17 00:00:00 2001 From: Wei <56273788+yuanweixin@users.noreply.github.com> Date: Mon, 1 May 2023 15:10:37 -0400 Subject: [PATCH 11/32] type:docs Update README.md (#1186) Change instruction to refer to `MODULE.bazel` instead of `MODULES.bazel`. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 089837de7d..a095a352c1 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,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 +161,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 From 2df3259c8e9c5f9dd538207166cdc67b1fcf4877 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Tue, 2 May 2023 09:38:02 -0700 Subject: [PATCH 12/32] fix: Allow passing a tuple to the `tags` attribute. (#1191) Starlark rules allow giving the tags as a tuple. The helper function that added the special migration tag assumed tags was always a list, resulting in an error when it tried to concatenate a list and tuple. To fix, check if tags is a tuple and concatenate a tuple if so. The input type of the tags attribute is preserved so that a test verifying tags can be passed to the underlying rule can be implemented (this test is to verify there isn't a regression during the rewrite to Starlark). --- docs/BUILD.bazel | 3 +++ python/private/BUILD.bazel | 6 ++++- python/private/util.bzl | 19 +++++++++++++++- tools/build_defs/python/tests/base_tests.bzl | 23 +++++++++++++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 27af3e7ed5..938ba85dd5 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -80,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/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/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) From 81a200be35ff62cd3b50c44968381b99aa4cd1cc Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Wed, 3 May 2023 12:52:28 -0600 Subject: [PATCH 13/32] tests: Add skylib to various test dependencies to fix CI (#1199) This fixes a problem where bazel skylib does not load during the toolchain integration test. The skylib dependency was introduced by #1191, but skylib was not present in the WORKSPACE configs of several things. To fix, skylib just needs to be added to the workspace files. --- internal_deps.bzl | 3 +++ .../toolchains/workspace_template/WORKSPACE.tmpl | 12 ++++++++++++ tests/ignore_root_user_error/WORKSPACE | 15 +++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/internal_deps.bzl b/internal_deps.bzl index 86a53b25e7..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", 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/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() From 96b4fa13b9dfcf32422455931621598eb99d28f5 Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Wed, 3 May 2023 14:56:31 -0600 Subject: [PATCH 14/32] feat: removing bzlmod from example (#1200) Having both bzlmod and a WORKSPACE file confuses the user, and I have #1155 which adds a new example for gazelle and bzlmod. --- .bazelci/presubmit.yml | 26 ----------- examples/build_file_generation/MODULE.bazel | 43 ------------------- .../build_file_generation/WORKSPACE.bzlmod | 2 - 3 files changed, 71 deletions(-) delete mode 100644 examples/build_file_generation/MODULE.bazel delete mode 100644 examples/build_file_generation/WORKSPACE.bzlmod diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 7b5ba8b2f2..8ad04894d9 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -147,32 +147,6 @@ tasks: working_directory: examples/build_file_generation platform: windows - integration_test_build_file_generation_bzlmod_ubuntu: - <<: *minimum_supported_bzlmod_version - <<: *common_bzlmod_flags - <<: *reusable_build_test_all - name: build_file_generation_bzlmod integration tests on Ubuntu - working_directory: examples/build_file_generation - platform: ubuntu2004 - integration_test_build_file_generation_bzlmod_debian: - <<: *common_bzlmod_flags - <<: *reusable_build_test_all - name: build_file_generation_bzlmod integration tests on Debian - working_directory: examples/build_file_generation - platform: debian11 - integration_test_build_file_generation_bzlmod_macos: - <<: *common_bzlmod_flags - <<: *reusable_build_test_all - name: build_file_generation_bzlmod integration tests on macOS - working_directory: examples/build_file_generation - platform: macos - integration_test_build_file_generation_bzlmod_windows: - <<: *common_bzlmod_flags - <<: *reusable_build_test_all - name: build_file_generation_bzlmod integration tests on Windows - working_directory: examples/build_file_generation - platform: windows - integration_test_bzlmod_ubuntu_min: <<: *minimum_supported_bzlmod_version <<: *reusable_build_test_all 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/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 From e40079186ddd403cbad6a0e951363d1c5bf9238a Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Wed, 3 May 2023 15:01:31 -0600 Subject: [PATCH 15/32] feat: propagate visibility attribute for py_wheel publishing (#1203) py_wheel does not propagate "visibility" attribute to the "publish" rule. The visibility attribute on py_wheel target is not propagated to the auto-generated "publish" target. This commit adds the visibility attribute. Closes: https://github.com/bazelbuild/rules_python/issues/1192 --- python/packaging.bzl | 1 + 1 file changed, 1 insertion(+) 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 From fc94642ed05a1f3a851487f9bce84e5f5317c926 Mon Sep 17 00:00:00 2001 From: Martin Medler <36563496+martis42@users.noreply.github.com> Date: Wed, 3 May 2023 23:30:24 +0200 Subject: [PATCH 16/32] docs: fix typos in pip_repository docs (#1202) --- docs/pip_repository.md | 4 ++-- python/pip_install/pip_repository.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pip_repository.md b/docs/pip_repository.md index c02058e08d..99af4bac81 100644 --- a/docs/pip_repository.md +++ b/docs/pip_repository.md @@ -66,7 +66,7 @@ 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 | @@ -130,7 +130,7 @@ 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 | diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index 1ea7bca88a..f58c2afddb 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -536,7 +536,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, From 532f07a9930ef8d218b7415e373e31dc2006d75c Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Wed, 3 May 2023 15:02:32 -0700 Subject: [PATCH 17/32] tests: Force analysis test labels to resolve within @rules_python context (#1187) When a string label is passed to the `@rules_testing` analysis_test functions, the strings are evaluated within the context of @rules_testing because that is where the actual rule invocation happens. Without bzlmod, this just requires qualifying the labels with the repo name (which is what was being done) because there's just a flat global namespace of repos. With bzlmod enabled, repo mapping happens, so rules_testing tries to resolve those repo names using its repo mapping, which doesn't work because rules_testing's mapping doesn't include every repo using it. --- .../python/tests/py_test/py_test_tests.bzl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 560883200a..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], }, ) From 262c699f71c65bb778a15ba992bca091a851e35b Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Fri, 5 May 2023 02:36:34 +0900 Subject: [PATCH 18/32] fix(update_deleted_packages.sh): allow to run from anywhere in the repo (#1206) It seems that the tool was correctly trying to modify the `.bazelrc` at the root of the repo, but the `find` execution would run in the `$PWD`. This change ensures that the `find` is consistent with the file we are trying to modify and allows the user to execute the script from anywhere in the repo. Tested: 1. Update the deleted packages with the version of the script at HEAD 1. Fix the bug 1. Rerun the script from the 'tests' sub-folder in the repo to ensure that running the script is noop. 1. Revert the changes to '.bazelrc' to reduce conflicts as other PRs are modifying it. Work towards #958. --- tools/bazel_integration_test/update_deleted_packages.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/bazel_integration_test/update_deleted_packages.sh b/tools/bazel_integration_test/update_deleted_packages.sh index ce7b05ada7..e21f88706a 100755 --- a/tools/bazel_integration_test/update_deleted_packages.sh +++ b/tools/bazel_integration_test/update_deleted_packages.sh @@ -16,9 +16,11 @@ # For integration tests, we want to be able to glob() up the sources inside a nested package # See explanation in .bazelrc -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, -\ From 0912bba35d0f3e341c7beae206b21e9ca5b8322e Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Thu, 4 May 2023 14:08:34 -0600 Subject: [PATCH 19/32] feat(bzlmod): expose platform-agnostic repo target for toolchain interpreter (#1155) This exposes a new repo and target, `@{name}_host_interpreter//:python`, created by `python.toolchain()`, that points to the host OS's Python interpreter for that particular toolchain. This solves two problems: 1. `pip.parse()` can now refer to the same interpreter used in the toolchains 2. There is now a canonical, public, way to refer to the host OS Python interpreter for repository rules. The above were _sort of_ possible for users to do already, but it required them to write much more configuration and extension code to do so. This moves that sort of boilerplate into our code so they have a simpler configuration. Also: - removing bzlmod support in the build_file_generation example; making examples work with both WORKSPACE and MODULE is a pain, hence splitting them. - adding an example of bzlmod and gazelle - improved documentation in the pip arguments Closes: https://github.com/bazelbuild/rules_python/issues/1161 --- .bazelci/presubmit.yml | 42 ++ .bazelrc | 4 +- docs/pip_repository.md | 4 +- examples/BUILD.bazel | 5 + examples/build_file_generation/.bazelrc | 2 +- examples/bzlmod/gazelle_python.yaml | 590 ++++++++++++++++++ examples/bzlmod/runfiles/BUILD.bazel | 1 + .../bzlmod_build_file_generation/.bazelignore | 1 + .../bzlmod_build_file_generation/.bazelrc | 9 + .../.bazelversion | 1 + .../bzlmod_build_file_generation/.gitignore | 1 + .../bzlmod_build_file_generation/BUILD.bazel | 103 +++ .../bzlmod_build_file_generation/MODULE.bazel | 113 ++++ .../bzlmod_build_file_generation/README.md | 28 + .../bzlmod_build_file_generation/WORKSPACE | 2 + .../bzlmod_build_file_generation/__main__.py | 18 + .../bzlmod_build_file_generation/__test__.py | 33 + .../gazelle_python.yaml | 590 ++++++++++++++++++ examples/bzlmod_build_file_generation/lib.py | 19 + .../other_module/MODULE.bazel | 5 + .../other_module/WORKSPACE | 0 .../other_module/other_module/pkg/BUILD.bazel | 11 + .../other_module/pkg/data/data.txt | 1 + .../other_module/other_module/pkg/lib.py | 27 + .../requirements.in | 6 + .../requirements_lock.txt | 227 +++++++ .../requirements_windows.txt | 231 +++++++ .../runfiles/BUILD.bazel | 19 + .../runfiles/data/data.txt | 1 + .../runfiles/runfiles_test.py | 64 ++ gazelle/README.md | 43 +- python/extensions.bzl | 102 ++- python/pip_install/pip_repository.bzl | 2 +- 33 files changed, 2288 insertions(+), 17 deletions(-) create mode 100644 examples/bzlmod/gazelle_python.yaml create mode 100644 examples/bzlmod_build_file_generation/.bazelignore create mode 100644 examples/bzlmod_build_file_generation/.bazelrc create mode 100644 examples/bzlmod_build_file_generation/.bazelversion create mode 100644 examples/bzlmod_build_file_generation/.gitignore create mode 100644 examples/bzlmod_build_file_generation/BUILD.bazel create mode 100644 examples/bzlmod_build_file_generation/MODULE.bazel create mode 100644 examples/bzlmod_build_file_generation/README.md create mode 100644 examples/bzlmod_build_file_generation/WORKSPACE create mode 100644 examples/bzlmod_build_file_generation/__main__.py create mode 100644 examples/bzlmod_build_file_generation/__test__.py create mode 100644 examples/bzlmod_build_file_generation/gazelle_python.yaml create mode 100644 examples/bzlmod_build_file_generation/lib.py create mode 100644 examples/bzlmod_build_file_generation/other_module/MODULE.bazel create mode 100644 examples/bzlmod_build_file_generation/other_module/WORKSPACE create mode 100644 examples/bzlmod_build_file_generation/other_module/other_module/pkg/BUILD.bazel create mode 100644 examples/bzlmod_build_file_generation/other_module/other_module/pkg/data/data.txt create mode 100644 examples/bzlmod_build_file_generation/other_module/other_module/pkg/lib.py create mode 100644 examples/bzlmod_build_file_generation/requirements.in create mode 100644 examples/bzlmod_build_file_generation/requirements_lock.txt create mode 100644 examples/bzlmod_build_file_generation/requirements_windows.txt create mode 100644 examples/bzlmod_build_file_generation/runfiles/BUILD.bazel create mode 100644 examples/bzlmod_build_file_generation/runfiles/data/data.txt create mode 100644 examples/bzlmod_build_file_generation/runfiles/runfiles_test.py diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 8ad04894d9..b468970fbb 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -48,6 +48,8 @@ buildifier: test_targets: ["..."] .coverage_targets_example_bzlmod: &coverage_targets_example_bzlmod coverage_targets: ["//:test"] +.coverage_targets_example_bzlmod_build_file_generation: &coverage_targets_example_bzlmod_build_file_generation + coverage_targets: ["//:bzlmod_build_file_generation_test"] .coverage_targets_example_multi_python: &coverage_targets_example_multi_python coverage_targets: - //tests:my_lib_3_10_test @@ -179,6 +181,46 @@ tasks: working_directory: examples/bzlmod platform: windows + integration_test_bzlmod_generate_build_file_generation_ubuntu_min: + <<: *minimum_supported_bzlmod_version + <<: *reusable_build_test_all + <<: *coverage_targets_example_bzlmod_build_file_generation + name: example bzlmod build file min bazel version integration test + working_directory: examples/bzlmod_build_file_generation + platform: ubuntu2004 + integration_test_bzlmod_generation_build_files_ubuntu: + <<: *reusable_build_test_all + <<: *coverage_targets_example_bzlmod_build_file_generation + name: example bzlmod build file integration test + working_directory: examples/bzlmod_build_file_generation + platform: ubuntu2004 + integration_test_bzlmod_generation_build_files_ubuntu_run: + <<: *reusable_build_test_all + name: example bzlmod build file running gazelle and pip integration test + working_directory: examples/bzlmod_build_file_generation + platform: ubuntu2004 + shell_commands: + - "bazel run //:gazelle_python_manifest.update" + - "bazel run //:gazelle -- update" + integration_test_bzlmod_build_file_generation_debian: + <<: *reusable_build_test_all + <<: *coverage_targets_example_bzlmod_build_file_generation + name: example bzlmod build file integration test + working_directory: examples/bzlmod_build_file_generation + platform: debian11 + integration_test_bzlmod_build_file_generation_macos: + <<: *reusable_build_test_all + <<: *coverage_targets_example_bzlmod_build_file_generation + name: example bzlmod build file integration test + working_directory: examples/bzlmod_build_file_generation + platform: macos + integration_test_bzlmod_build_file_generation_windows: + <<: *reusable_build_test_all + # coverage is not supported on Windows + name: example bzlmod build file integration test + working_directory: examples/bzlmod_build_file_generation + platform: windows + integration_test_multi_python_versions_ubuntu_min: <<: *minimum_supported_version <<: *reusable_build_test_all diff --git a/.bazelrc b/.bazelrc index d607cdd9b7..e7e4af7bbd 100644 --- a/.bazelrc +++ b/.bazelrc @@ -3,8 +3,8 @@ # This lets us glob() up all the files inside the examples to make them inputs to tests # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it) # To update these lines, run tools/bazel_integration_test/update_deleted_packages.sh -build --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps -query --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps +build --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps +query --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps test --test_output=errors diff --git a/docs/pip_repository.md b/docs/pip_repository.md index 99af4bac81..29cb3d9c32 100644 --- a/docs/pip_repository.md +++ b/docs/pip_repository.md @@ -69,7 +69,7 @@ py_binary( | 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 | "" | @@ -133,7 +133,7 @@ Instantiated from pip_repository and inherits config options from there. | 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/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/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_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..781b0cba39 --- /dev/null +++ b/examples/bzlmod_build_file_generation/MODULE.bazel @@ -0,0 +1,113 @@ +# 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.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" + +# This is the name that is used for the host interpreter +PYTHON_INTERPRETER = PYTHON_NAME + "_host_interpreter" + +# 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) +use_repo(python, "python3_toolchains") +use_repo(python, PYTHON_INTERPRETER) + +# Register an already-defined toolchain so that Bazel can use it during toolchain resolution. +register_toolchains( + "@python3_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, + # The interpreter 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 = "@" + PYTHON_INTERPRETER + "//: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/gazelle/README.md b/gazelle/README.md index 2cd38764fc..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, ) ``` @@ -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/python/extensions.bzl b/python/extensions.bzl index 2b0c188554..3bcbb5023d 100644 --- a/python/extensions.bzl +++ b/python/extensions.bzl @@ -19,18 +19,24 @@ load("@rules_python//python/pip_install:pip_repository.bzl", "locked_requirement 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") +load("@rules_python//python/private:toolchains_repo.bzl", "get_host_os_arch", "get_host_platform") def _python_impl(module_ctx): for mod in module_ctx.modules: - for attr in mod.tags.toolchain: + for toolchain_attr in mod.tags.toolchain: python_register_toolchains( - name = attr.name, - python_version = attr.python_version, + 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 = attr.configure_coverage_tool, - ignore_root_user_error = attr.ignore_root_user_error, + register_coverage_tool = toolchain_attr.configure_coverage_tool, + ignore_root_user_error = toolchain_attr.ignore_root_user_error, + ) + host_hub_name = toolchain_attr.name + "_host_interpreter" + _host_hub( + name = host_hub_name, + user_repo_prefix = toolchain_attr.name, ) python = module_extension( @@ -127,3 +133,89 @@ pip = module_extension( "parse": tag_class(attrs = _pip_parse_ext_attrs()), }, ) + +# This function allows us to build the label name of a label +# that is not passed into the current context. +# The module_label is the key element that is passed in. +# This value provides the root location of the labels +# See https://bazel.build/external/extension#repository_names_and_visibility +def _repo_mapped_label(module_label, extension_name, apparent): + """Construct a canonical repo label accounting for repo mapping. + + Args: + module_label: Label object of the module hosting the extension; see + "_module" implicit attribute. + extension_name: str, name of the extension that created the repo in `apparent`. + apparent: str, a repo-qualified target string, but without the "@". e.g. + "python38_x86_linux//:python". The repo name should use the apparent + name used by the extension named by `ext_name` (i.e. the value of the + `name` arg the extension passes to repository rules) + """ + return Label("@@{module}~{extension_name}~{apparent}".format( + module = module_label.workspace_name, + extension_name = extension_name, + apparent = apparent, + )) + +# We are doing some bazel stuff here that could use an explanation. +# The basis of this function is that we need to create a symlink to +# the python binary that exists in a different repo that we know is +# setup by rules_python. +# +# We are building a Label like +# @@rules_python~override~python~python3_x86_64-unknown-linux-gnu//:python +# and then the function creates a symlink named python to that Label. +# The tricky part is the "~override~" part can't be known in advance +# and will change depending on how and what version of rules_python +# is used. To figure that part out, an implicit attribute is used to +# resolve the module's current name (see "_module" attribute) +# +# We are building the Label name dynamically, and can do this even +# though the Label is not passed into this function. If we choose +# not do this a user would have to write another 16 lines +# of configuration code, but we are able to save them that work +# because we know how rules_python works internally. We are using +# functions from private:toolchains_repo.bzl which is where the repo +# is being built. The repo name differs between host OS and platforms +# and the functions from toolchains_repo gives us this functions that +# information. +def _host_hub_impl(repo_ctx): + # Intentionally empty; this is only intended to be used by repository + # rules, which don't process build file contents. + repo_ctx.file("BUILD.bazel", "") + + # The two get_ functions we use are also utilized when building + # the repositories for the different interpreters. + (os, arch) = get_host_os_arch(repo_ctx) + host_platform = "{}_{}//:python".format( + repo_ctx.attr.user_repo_prefix, + get_host_platform(os, arch), + ) + + # the attribute is set to attr.label(default = "//:_"), which + # provides us the resolved, canonical, prefix for the module's repos. + # The extension_name "python" is determined by the + # name bound to the module_extension() call. + # We then have the OS and platform specific name of the python + # interpreter. + label = _repo_mapped_label(repo_ctx.attr._module, "python", host_platform) + + # create the symlink in order to set the interpreter for pip. + repo_ctx.symlink(label, "python") + +# We use this rule to set the pip interpreter target when using different operating +# systems with the same project +_host_hub = repository_rule( + implementation = _host_hub_impl, + local = True, + attrs = { + "user_repo_prefix": attr.string( + mandatory = True, + doc = """\ +The prefix to create the repository name. Usually the name you used when you created the +Python toolchain. +""", + ), + "_module": attr.label(default = "//:_"), + }, +) diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index f58c2afddb..032f23f47a 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -559,7 +559,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( From 23cf6b66baed3d884c82d9b005769e22d618c967 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Fri, 5 May 2023 07:36:08 +0900 Subject: [PATCH 20/32] fix(update_deleted_packages.sh): wheels example should not be included in .bazelrc (#1207) This correctly handles the integration tests and examples that are a part of the `rules_python` workspace and should not be included in the deleted packages list. This brings the changes made to the `.bazelrc` very close to what is in `main`, but I would like to update this later once #1155 and #1205 are merged. Fixes #919. --- .../update_deleted_packages.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/bazel_integration_test/update_deleted_packages.sh b/tools/bazel_integration_test/update_deleted_packages.sh index e21f88706a..54db02630f 100755 --- a/tools/bazel_integration_test/update_deleted_packages.sh +++ b/tools/bazel_integration_test/update_deleted_packages.sh @@ -15,6 +15,13 @@ # 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 -euxo pipefail @@ -23,5 +30,10 @@ 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 From 799e63fbc9c6dee95e07077689d7122c5736947f Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Mon, 8 May 2023 20:37:22 +0100 Subject: [PATCH 21/32] fix: Strip trailing newline from python output (#1212) This is used to generate a path, which shouldn't have a trailing newline. --- python/pip_install/pip_repository.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index 032f23f47a..5462f1b14d 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)) From 0efcd94d0ee6e1e56b27d25469c28502282fab5b Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Mon, 8 May 2023 13:12:56 -0700 Subject: [PATCH 22/32] fix: manually ignore bazel-* directories to make using custom Bazel builds easier (#1181) Normally, Bazel will ignore its convenience symlinks, so putting them in the .bazelignore file isn't necessary. However, when `--output_user_root` is set, which is beneficial to set when using different Bazel versions (it preserves the analysis cache between versions), the symlinks aren't ignored. Putting them in the bazelignore file fixes this. --- .bazelignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.bazelignore b/.bazelignore index e69de29bb2..a603a7bd8a 100644 --- a/.bazelignore +++ b/.bazelignore @@ -0,0 +1,8 @@ +# Normally these are ignored, but if you're using a custom +# build of Bazel with a custom --output_user_root value, Bazel +# tries to follow the symlinks of the other builds and finds +# the WORKSPACE, BUILD, etc files and tries to build them. +bazel-rules_python +bazel-bin +bazel-out +bazel-testlogs From d434f1047cfefc461829d5d90f5adcd6f0ef9e51 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Mon, 15 May 2023 02:04:44 +0900 Subject: [PATCH 23/32] test(bzlmod): explicitly enable bzlmod in the test harness (#1204) Previously we would depend on the value of .bazelrc and this change ensures that we are explicitly enable bzlmod via CLI args. It seems that the `py_proto_library` integration tests defined in the `//examples:BUILD.bazel` file were not running using `bzlmod` before hand, however, they were correctly executed in the CI. Work towards #958. --- tools/bazel_integration_test/test_runner.py | 1 + 1 file changed, 1 insertion(+) 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 From ccea92a3ad6f9204a172d306a6b1c4cb18e41cee Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Mon, 15 May 2023 10:24:43 -0600 Subject: [PATCH 24/32] feat(bzlmod): Cleaning up interpreter resolution (#1218) This commit cleans up the use of "canonical resolution" of the Python interpreter. When the extension toolchains run it collects a list of the interpreters and then uses the hub_repo rule to create a map of names and the interpreter labels. Next, we then use the interpreter_extension that, creates reports that have symlinks pointing to the different interpreter binaries. The user can then pass in a label to the pip call for the specific hermetic interpreter. --- MODULE.bazel | 3 + .../bzlmod_build_file_generation/MODULE.bazel | 34 +++--- python/extensions.bzl | 104 ++---------------- python/interpreter_extension.bzl | 75 +++++++++++++ python/private/interpreter_hub.bzl | 58 ++++++++++ 5 files changed, 168 insertions(+), 106 deletions(-) create mode 100644 python/interpreter_extension.bzl create mode 100644 python/private/interpreter_hub.bzl diff --git a/MODULE.bazel b/MODULE.bazel index 92da4020b9..e490beb73c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -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.bzl", "python") +use_repo(python, "pythons_hub") diff --git a/examples/bzlmod_build_file_generation/MODULE.bazel b/examples/bzlmod_build_file_generation/MODULE.bazel index 781b0cba39..d59fbb3cea 100644 --- a/examples/bzlmod_build_file_generation/MODULE.bazel +++ b/examples/bzlmod_build_file_generation/MODULE.bazel @@ -48,9 +48,6 @@ python = use_extension("@rules_python//python:extensions.bzl", "python") # We also use the same name for python.host_python_interpreter. PYTHON_NAME = "python3" -# This is the name that is used for the host interpreter -PYTHON_INTERPRETER = PYTHON_NAME + "_host_interpreter" - # We next initialize the python toolchain using the extension. # You can set different Python versions in this block. python.toolchain( @@ -66,37 +63,46 @@ python.toolchain( # 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) -use_repo(python, "python3_toolchains") -use_repo(python, PYTHON_INTERPRETER) +use_repo(python, PYTHON_NAME, "python3_toolchains") -# Register an already-defined toolchain so that Bazel can use it during toolchain resolution. +# Register an already-defined toolchain so that Bazel can use it during +# toolchain resolution. register_toolchains( "@python3_toolchains//:all", ) -# Use the pip extension -pip = use_extension("@rules_python//python:extensions.bzl", "pip") +# 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:interpreter_extension.bzl", "interpreter") +interpreter.install( + name = "interpreter_python3", + python_name = PYTHON_NAME, +) +use_repo(interpreter, "interpreter_python3") -# 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. +# 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.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 attribute points to the interpreter to use for running - # pip commands to download the packages in the requirements file. + # 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 = "@" + PYTHON_INTERPRETER + "//:python", + python_interpreter_target = "@interpreter_python3//:python", requirements_lock = "//:requirements_lock.txt", requirements_windows = "//:requirements_windows.txt", ) diff --git a/python/extensions.bzl b/python/extensions.bzl index 3bcbb5023d..ce110693ee 100644 --- a/python/extensions.bzl +++ b/python/extensions.bzl @@ -19,9 +19,10 @@ load("@rules_python//python/pip_install:pip_repository.bzl", "locked_requirement 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") -load("@rules_python//python/private:toolchains_repo.bzl", "get_host_os_arch", "get_host_platform") +load("@rules_python//python/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( @@ -33,11 +34,16 @@ def _python_impl(module_ctx): register_coverage_tool = toolchain_attr.configure_coverage_tool, ignore_root_user_error = toolchain_attr.ignore_root_user_error, ) - host_hub_name = toolchain_attr.name + "_host_interpreter" - _host_hub( - name = host_hub_name, - user_repo_prefix = toolchain_attr.name, - ) + + # 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( implementation = _python_impl, @@ -133,89 +139,3 @@ pip = module_extension( "parse": tag_class(attrs = _pip_parse_ext_attrs()), }, ) - -# This function allows us to build the label name of a label -# that is not passed into the current context. -# The module_label is the key element that is passed in. -# This value provides the root location of the labels -# See https://bazel.build/external/extension#repository_names_and_visibility -def _repo_mapped_label(module_label, extension_name, apparent): - """Construct a canonical repo label accounting for repo mapping. - - Args: - module_label: Label object of the module hosting the extension; see - "_module" implicit attribute. - extension_name: str, name of the extension that created the repo in `apparent`. - apparent: str, a repo-qualified target string, but without the "@". e.g. - "python38_x86_linux//:python". The repo name should use the apparent - name used by the extension named by `ext_name` (i.e. the value of the - `name` arg the extension passes to repository rules) - """ - return Label("@@{module}~{extension_name}~{apparent}".format( - module = module_label.workspace_name, - extension_name = extension_name, - apparent = apparent, - )) - -# We are doing some bazel stuff here that could use an explanation. -# The basis of this function is that we need to create a symlink to -# the python binary that exists in a different repo that we know is -# setup by rules_python. -# -# We are building a Label like -# @@rules_python~override~python~python3_x86_64-unknown-linux-gnu//:python -# and then the function creates a symlink named python to that Label. -# The tricky part is the "~override~" part can't be known in advance -# and will change depending on how and what version of rules_python -# is used. To figure that part out, an implicit attribute is used to -# resolve the module's current name (see "_module" attribute) -# -# We are building the Label name dynamically, and can do this even -# though the Label is not passed into this function. If we choose -# not do this a user would have to write another 16 lines -# of configuration code, but we are able to save them that work -# because we know how rules_python works internally. We are using -# functions from private:toolchains_repo.bzl which is where the repo -# is being built. The repo name differs between host OS and platforms -# and the functions from toolchains_repo gives us this functions that -# information. -def _host_hub_impl(repo_ctx): - # Intentionally empty; this is only intended to be used by repository - # rules, which don't process build file contents. - repo_ctx.file("BUILD.bazel", "") - - # The two get_ functions we use are also utilized when building - # the repositories for the different interpreters. - (os, arch) = get_host_os_arch(repo_ctx) - host_platform = "{}_{}//:python".format( - repo_ctx.attr.user_repo_prefix, - get_host_platform(os, arch), - ) - - # the attribute is set to attr.label(default = "//:_"), which - # provides us the resolved, canonical, prefix for the module's repos. - # The extension_name "python" is determined by the - # name bound to the module_extension() call. - # We then have the OS and platform specific name of the python - # interpreter. - label = _repo_mapped_label(repo_ctx.attr._module, "python", host_platform) - - # create the symlink in order to set the interpreter for pip. - repo_ctx.symlink(label, "python") - -# We use this rule to set the pip interpreter target when using different operating -# systems with the same project -_host_hub = repository_rule( - implementation = _host_hub_impl, - local = True, - attrs = { - "user_repo_prefix": attr.string( - mandatory = True, - doc = """\ -The prefix to create the repository name. Usually the name you used when you created the -Python toolchain. -""", - ), - "_module": attr.label(default = "//:_"), - }, -) diff --git a/python/interpreter_extension.bzl b/python/interpreter_extension.bzl new file mode 100644 index 0000000000..b9afe1abda --- /dev/null +++ b/python/interpreter_extension.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/private/interpreter_hub.bzl b/python/private/interpreter_hub.bzl new file mode 100644 index 0000000000..f1ca670cf2 --- /dev/null +++ b/python/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, + ), + }, +) From 46537cf32f8bf722a6be805821cb2ee17d7b936a Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Mon, 15 May 2023 16:04:40 -0600 Subject: [PATCH 25/32] feat(bzlmod)!: Move each bzlmod extension into its own file (#1226) This commit refactors the files that contain the bzlmod extensions. - All extensions are moved under the new extensions folder - Private extensions are moved under extensions/private - All extension files are renamed to remove the _extension suffix - pip and internal_deps extensions are moved to their own file This commit organizes the extensions better and also follows the best practice of having a single extension per file. Having each extension in its own file allows them to use some additional features while helping avoid backwards incompatible changes. ## BREAKING CHANGES This splits `//python:extensions.bzl`, which previously held the `python` and `pip` extensions, into separate files (`python.bzl` and `pip.bzl`, respectively). Unfortunately, moving the location of the extensions is a breaking change due to how bzlmod extension identity works (see https://bazel.build/external/extension#extension_identity). Fortunately, by moving to one extension per file, we shouldn't have to ever do this again. Users must update the file path in their `use_repo()` statements as follows: * `use_extension("@rules_python//python:extensions.bzl", "python")` -> `use_extension("@rules_python//python/extensions:python.bzl", "python")` * `use_extension("@rules_python//python:extensions.bzl", "pip")` -> `use_extension("@rules_python//python/extensions:pip.bzl", "pip")` The following `sed` commands should approximate the necessary changes: ``` sed 'sXuse_extension("@rules_python//python:extensions.bzl", "python")Xuse_extension("@rules_python//python/extensions:python.bzl", "python")X'` sed 'sXuse_extension("@rules_python//python:extensions.bzl", "pip")Xuse_extension("@rules_python//python/extensions:pip.bzl", "pip")X'` ``` See `examples/bzlmod_build_file_generation/MODULE.bazel` for an example of the new paths. --- MODULE.bazel | 4 +- examples/bzlmod/MODULE.bazel | 4 +- .../bzlmod_build_file_generation/MODULE.bazel | 6 +- examples/py_proto_library/MODULE.bazel | 2 +- python/extensions/BUILD.bazel | 23 +++++++ .../interpreter.bzl} | 0 python/{extensions.bzl => extensions/pip.bzl} | 67 ++----------------- python/extensions/private/BUILD.bazel | 23 +++++++ python/extensions/private/internal_deps.bzl | 25 +++++++ .../private/interpreter_hub.bzl | 0 python/extensions/python.bzl | 64 ++++++++++++++++++ 11 files changed, 148 insertions(+), 70 deletions(-) create mode 100644 python/extensions/BUILD.bazel rename python/{interpreter_extension.bzl => extensions/interpreter.bzl} (100%) rename python/{extensions.bzl => extensions/pip.bzl} (60%) create mode 100644 python/extensions/private/BUILD.bazel create mode 100644 python/extensions/private/internal_deps.bzl rename python/{ => extensions}/private/interpreter_hub.bzl (100%) create mode 100644 python/extensions/python.bzl diff --git a/MODULE.bazel b/MODULE.bazel index e490beb73c..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, @@ -47,5 +47,5 @@ use_repo( "pypi__coverage_cp39_x86_64-unknown-linux-gnu", ) -python = use_extension("@rules_python//python:extensions.bzl", "python") +python = use_extension("@rules_python//python/extensions:python.bzl", "python") use_repo(python, "pythons_hub") diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel index ce9122810c..61d7967d5e 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -10,7 +10,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, @@ -23,7 +23,7 @@ register_toolchains( "@python3_9_toolchains//:all", ) -pip = use_extension("@rules_python//python:extensions.bzl", "pip") +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( name = "pip", requirements_lock = "//:requirements_lock.txt", diff --git a/examples/bzlmod_build_file_generation/MODULE.bazel b/examples/bzlmod_build_file_generation/MODULE.bazel index d59fbb3cea..179fe1bdea 100644 --- a/examples/bzlmod_build_file_generation/MODULE.bazel +++ b/examples/bzlmod_build_file_generation/MODULE.bazel @@ -42,7 +42,7 @@ 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.bzl", "python") +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. @@ -74,7 +74,7 @@ register_toolchains( # 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:interpreter_extension.bzl", "interpreter") +interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter") interpreter.install( name = "interpreter_python3", python_name = PYTHON_NAME, @@ -88,7 +88,7 @@ use_repo(interpreter, "interpreter_python3") # 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.bzl", "pip") +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( name = "pip", # When using gazelle you must use set the following flag 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/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/interpreter_extension.bzl b/python/extensions/interpreter.bzl similarity index 100% rename from python/interpreter_extension.bzl rename to python/extensions/interpreter.bzl diff --git a/python/extensions.bzl b/python/extensions/pip.bzl similarity index 60% rename from python/extensions.bzl rename to python/extensions/pip.bzl index ce110693ee..2ec2bbf404 100644 --- a/python/extensions.bzl +++ b/python/extensions/pip.bzl @@ -12,71 +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") -load("@rules_python//python/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( - 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: @@ -134,6 +73,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/private/interpreter_hub.bzl b/python/extensions/private/interpreter_hub.bzl similarity index 100% rename from python/private/interpreter_hub.bzl rename to python/extensions/private/interpreter_hub.bzl 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), + }, + ), + }, +) From 9268d919e5fb5b0e7f010c77960de6e2b6ff10ee Mon Sep 17 00:00:00 2001 From: Chris Love <335402+chrislovecnm@users.noreply.github.com> Date: Mon, 15 May 2023 16:05:53 -0600 Subject: [PATCH 26/32] Adding bzlmod support document (#1214) This markdown file maintains the current status of our bzlmod implementation. Created section in README and linked to the bzlmod doc. --- BZLMOD_SUPPORT.md | 37 +++++++++++++++++++++++++++++++++++++ README.md | 7 +++++++ 2 files changed, 44 insertions(+) create mode 100644 BZLMOD_SUPPORT.md diff --git a/BZLMOD_SUPPORT.md b/BZLMOD_SUPPORT.md new file mode 100644 index 0000000000..cf95d12a0e --- /dev/null +++ b/BZLMOD_SUPPORT.md @@ -0,0 +1,37 @@ +# Bzlmod support + +## `rule_python` `bzlmod` support + +- Status: Beta +- Full Feature Parity: No + +Some features are missing or broken, and the public APIs are not yet stable. + +## Configuration + +The releases page will give you the latest version number, and a basic example. The release page is located [here](/bazelbuild/rules_python/releases). + +## What is bzlmod? + +> Bazel supports external dependencies, source files (both text and binary) used in your build that are not from your workspace. For example, they could be a ruleset hosted in a GitHub repo, a Maven artifact, or a directory on your local machine outside your current workspace. +> +> As of Bazel 6.0, there are two ways to manage external dependencies with Bazel: the traditional, repository-focused WORKSPACE system, and the newer module-focused MODULE.bazel system (codenamed Bzlmod, and enabled with the flag `--enable_bzlmod`). The two systems can be used together, but Bzlmod is replacing the WORKSPACE system in future Bazel releases. +> -- https://bazel.build/external/overview + +## Examples + +We have two examples that demonstrate how to configure `bzlmod`. + +The first example is in [examples/bzlmod](examples/bzlmod), and it demonstrates basic bzlmod configuration. +A user does not use `local_path_override` stanza and would define the version in the `bazel_dep` line. + +A second example, in [examples/bzlmod_build_file_generation](examples/bzlmod_build_file_generation) demonstrates the use of `bzlmod` to configure `gazelle` support for `rules_python`. + +## Feature parity + +This rule set does not have full feature partity with the older `WORKSPACE` type configuration: + +1. Multiple python versions are not yet supported, as demonstrated in [this](examples/multi_python_versions) example. +2. Gazelle does not support finding deps in sub-modules. For instance we can have a dep like ` "@our_other_module//other_module/pkg:lib",` in a `py_test` definition. + +Check ["issues"](/bazelbuild/rules_python/issues) for an up to date list. diff --git a/README.md b/README.md index a095a352c1..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 From 16126d0ebfee074a3a8fe216b20cc19e1b3603c1 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Tue, 16 May 2023 13:11:28 +0900 Subject: [PATCH 27/32] test(coverage): add a test to check the sys.path under bzlmod (#1223) Whilst it is for documentation purposes for maintainers it is also a regression test for #1045. Also add a test to ensure that the `html` module is not shadowed when running under `coverage`. Fixes #1196. --- examples/bzlmod/test.py | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) 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( """\ From 07e68569848afc374043193541ea5f7d791c4769 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Wed, 17 May 2023 13:18:09 +0900 Subject: [PATCH 28/32] fix(toolchain): set correct return attrs to remove non-hermeticity warning (#1231) Fixes the incorrect debug statement when downloading the toolchain for the first time asking users to replace "urls" with "url" in the toolchain definition which we maintain: ``` $ bazel build ... ... indicated that a canonical reproducible form can be obtained by modifying ... ``` Even though this is seen only once by the user, it may confuse them. Summary of changes: - refactor(toolchain): rename a local variable url -> urls - fix(toolchain): set url return attrs correctly --- python/repositories.bzl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) 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.", From 02ace45bbc4006b025aaae3fa02d9e79fc85f4e0 Mon Sep 17 00:00:00 2001 From: Matt Oberle Date: Wed, 17 May 2023 00:22:24 -0400 Subject: [PATCH 29/32] fix: allow url fragments in requirements file (#1195) This commit addresses issue #1194 (see issue for details). It brings the `comment` detection of `requirements_parser.bzl` closer to the spec described here: - https://pip.pypa.io/en/stable/reference/requirements-file-format/#comments 1. Lines that begin with `#` are comments. 2. Content after (and including) ` #` is a comment. Prior to this commit, a dependency like this would result in invalid `pip wheel` arguments: ``` requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49 ``` --- .../private/test/requirements_parser_tests.bzl | 8 ++++++++ python/pip_install/requirements_parser.bzl | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/python/pip_install/private/test/requirements_parser_tests.bzl b/python/pip_install/private/test/requirements_parser_tests.bzl index c13ec204fb..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) 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) From 28bc03cd664de130cf78a2fd43109939b9ea2eb2 Mon Sep 17 00:00:00 2001 From: Ofey Chan Date: Wed, 17 May 2023 12:31:14 +0800 Subject: [PATCH 30/32] fix: `example/build_file_generation/README.md` (#1164) This PR updates outdated README.md of example. Closes #1160 --------- Signed-off-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> Co-authored-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> --- examples/build_file_generation/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 1383bd4fa06c7c449156913f123c452533cdd724 Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin Date: Wed, 17 May 2023 10:08:33 -0700 Subject: [PATCH 31/32] fix: Using canonical name in requirements.bzl (#1176) When `incompatible_generate_aliases = False`, `pip.parse` doesn't work in bzlmod, because requirements.bzl has: ``` all_requirements = ["@rules_python~0.21.0~pip~pip_yapf//:pkg"] all_whl_requirements = ["@rules_python~0.21.0~pip~pip_yapf//:whl"] ``` Starting Bazel 6, canonical names should be referred with double "@". The reason why `incompatible_generate_aliases = True` worked is because it uses apparent name by parsing the canonical label with `repo_name = rctx.attr.name.split("~")[-1]`. This is dangerous because Bazel may change its canonical name pattern in future versions. This PR adds a new attribute "repo_name" to `pip_repository_bzlmod`, so we have access to the human-readable name in the implementation. --- docs/pip_repository.md | 6 ++++-- examples/bzlmod/BUILD.bazel | 13 ++++++++++++- examples/bzlmod/MODULE.bazel | 3 +++ python/extensions/pip.bzl | 1 + python/pip_install/pip_repository.bzl | 10 +++++++--- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/docs/pip_repository.md b/docs/pip_repository.md index 29cb3d9c32..7d539c9c44 100644 --- a/docs/pip_repository.md +++ b/docs/pip_repository.md @@ -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 | diff --git a/examples/bzlmod/BUILD.bazel b/examples/bzlmod/BUILD.bazel index 7ecc035853..3183608897 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") @@ -43,3 +44,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 61d7967d5e..d2d7d63871 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -4,6 +4,7 @@ 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", @@ -26,6 +27,8 @@ register_toolchains( 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, requirements_lock = "//:requirements_lock.txt", requirements_windows = "//:requirements_windows.txt", ) diff --git a/python/extensions/pip.bzl b/python/extensions/pip.bzl index 2ec2bbf404..ce5eea30d4 100644 --- a/python/extensions/pip.bzl +++ b/python/extensions/pip.bzl @@ -34,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, ) diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index 5462f1b14d..406e12113d 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -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 @@ -379,11 +379,11 @@ def _pip_repository_bzlmod_impl(rctx): 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, @@ -395,6 +395,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", From 693a1587baf055979493565933f8f40225c00c6d Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Fri, 19 May 2023 00:12:13 +0900 Subject: [PATCH 32/32] feat(bzlmod): support entry_point macro (#1220) Add `entry_point` macro to the repo generated by the `pip.parse` extension. This works by using the canonical label literal, so should work without users needing to add the spoke repos to the `use_repo` statement. We test this by having an extra folder in the `bzlmod` example. Fixes #958. --- .bazelrc | 4 +- examples/bzlmod/BUILD.bazel | 1 + examples/bzlmod/MODULE.bazel | 8 ++++ examples/bzlmod/entry_point/BUILD.bazel | 20 +++++++++ .../bzlmod/entry_point/test_entry_point.py | 43 +++++++++++++++++++ python/pip_install/pip_repository.bzl | 1 + ...ip_repository_requirements_bzlmod.bzl.tmpl | 7 +++ 7 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 examples/bzlmod/entry_point/BUILD.bazel create mode 100644 examples/bzlmod/entry_point/test_entry_point.py diff --git a/.bazelrc b/.bazelrc index e7e4af7bbd..fe542b3722 100644 --- a/.bazelrc +++ b/.bazelrc @@ -3,8 +3,8 @@ # This lets us glob() up all the files inside the examples to make them inputs to tests # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it) # To update these lines, run tools/bazel_integration_test/update_deleted_packages.sh -build --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps -query --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps +build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points +query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points test --test_output=errors diff --git a/examples/bzlmod/BUILD.bazel b/examples/bzlmod/BUILD.bazel index 3183608897..e1f5790631 100644 --- a/examples/bzlmod/BUILD.bazel +++ b/examples/bzlmod/BUILD.bazel @@ -35,6 +35,7 @@ py_binary( py_test( name = "test", srcs = ["test.py"], + main = "test.py", deps = [":lib"], ) diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel index d2d7d63871..145cebd276 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -24,11 +24,19 @@ register_toolchains( "@python3_9_toolchains//:all", ) +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/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index 406e12113d..5239fd5f9c 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -387,6 +387,7 @@ def _pip_repository_bzlmod_impl(rctx): for p in bzl_packages ]), "%%MACRO_TMPL%%": macro_tmpl, + "%%NAME%%": rctx.attr.name, "%%REQUIREMENTS_LOCK%%": str(requirements_txt), }) diff --git a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl index 1b2e2178bb..b77bf39c38 100644 --- a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl +++ b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl @@ -22,3 +22,10 @@ def data_requirement(name): def dist_info_requirement(name): 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)