aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2024-01-16 16:42:56 -0800
committerYifan Hong <elsk@google.com>2024-01-16 16:42:57 -0800
commit1508c18d9e27325a8d9c574a90d205e0a1d8a78f (patch)
tree721d3225371f656a66228a41796c81aa4d8bc096
parent3e21f23d9400ba51f10e9b76016ff6d472829b4e (diff)
parent231d3f633fbcbb36028d96a188298df99bf153e1 (diff)
downloadbazelbuild-rules_python-1508c18d9e27325a8d9c574a90d205e0a1d8a78f.tar.gz
Upgrade bazelbuild-rules_python to 0.28.0
This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update bazelbuild-rules_python For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Test: TreeHugger Change-Id: Ic0584645f577a4ea1f67458ca5e753f8a906aaa4
-rw-r--r--.bazelci/presubmit.yml456
-rw-r--r--.bazelignore17
-rw-r--r--.bazelrc17
-rw-r--r--.bazelversion2
-rw-r--r--.bcr/config.yml2
-rw-r--r--.gitattributes1
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md4
-rwxr-xr-x.github/workflows/create_archive_and_notes.sh3
-rw-r--r--.github/workflows/mypy.yaml32
-rw-r--r--.pre-commit-config.yaml8
-rw-r--r--.readthedocs.yml14
-rw-r--r--BUILD.bazel16
-rw-r--r--CHANGELOG.md336
-rw-r--r--CONTRIBUTING.md95
-rw-r--r--DEVELOPING.md11
-rw-r--r--METADATA24
-rw-r--r--MODULE.bazel58
-rw-r--r--README.md341
-rw-r--r--WORKSPACE65
-rw-r--r--docs/BUILD.bazel175
-rwxr-xr-xdocs/packaging.md211
-rw-r--r--docs/pip.md273
-rw-r--r--docs/pip_repository.md242
-rw-r--r--docs/py_cc_toolchain.md32
-rw-r--r--docs/py_cc_toolchain_info.md27
-rwxr-xr-xdocs/python.md227
-rw-r--r--docs/sphinx/BUILD.bazel123
-rw-r--r--docs/sphinx/README.md72
-rw-r--r--docs/sphinx/_includes/py_console_script_binary.md64
-rw-r--r--docs/sphinx/_stardoc_footer.md15
-rw-r--r--docs/sphinx/_static/css/custom.css43
-rw-r--r--docs/sphinx/api/index.md6
-rw-r--r--docs/sphinx/bazel_inventory.txt17
-rw-r--r--docs/sphinx/conf.py150
-rw-r--r--docs/sphinx/coverage.md (renamed from docs/coverage.md)4
-rw-r--r--docs/sphinx/gazelle.md9
-rw-r--r--docs/sphinx/getting-started.md181
-rw-r--r--docs/sphinx/glossary.md28
-rw-r--r--docs/sphinx/index.md69
-rw-r--r--docs/sphinx/pip.md84
-rw-r--r--docs/sphinx/pypi-dependencies.md217
-rw-r--r--docs/sphinx/pyproject.toml13
-rwxr-xr-xdocs/sphinx/readthedocs_build.sh20
-rw-r--r--docs/sphinx/requirements.txt341
-rw-r--r--docs/sphinx/support.md61
-rw-r--r--examples/BUILD.bazel57
-rw-r--r--examples/build_file_generation/.bazelrc4
-rw-r--r--examples/build_file_generation/BUILD.bazel9
-rw-r--r--examples/build_file_generation/WORKSPACE35
-rw-r--r--examples/build_file_generation/__init__.py1
-rw-r--r--examples/build_file_generation/gazelle_python.yaml713
-rw-r--r--examples/build_file_generation/random_number_generator/BUILD.bazel2
-rw-r--r--examples/build_file_generation/requirements.in2
-rw-r--r--examples/build_file_generation/requirements_lock.txt180
-rw-r--r--examples/build_file_generation/requirements_windows.txt342
-rw-r--r--examples/bzlmod/BUILD.bazel8
-rw-r--r--examples/bzlmod/MODULE.bazel72
-rw-r--r--examples/bzlmod/MODULE.bazel.lock4157
-rw-r--r--examples/bzlmod/entry_point/BUILD.bazel20
-rw-r--r--examples/bzlmod/entry_points/BUILD.bazel33
-rw-r--r--examples/bzlmod/entry_points/tests/BUILD.bazel63
-rw-r--r--examples/bzlmod/entry_points/tests/file_with_pylint_errors.py6
-rw-r--r--examples/bzlmod/entry_points/tests/pylint_deps_test.py72
-rw-r--r--examples/bzlmod/entry_points/tests/pylint_test.py57
-rw-r--r--examples/bzlmod/entry_points/tests/yamllint_test.py (renamed from examples/bzlmod/entry_point/test_entry_point.py)16
-rw-r--r--examples/bzlmod/gazelle_python.yaml590
-rw-r--r--examples/bzlmod/lib.py2
-rw-r--r--examples/bzlmod/other_module/BUILD.bazel9
-rw-r--r--examples/bzlmod/other_module/MODULE.bazel32
-rw-r--r--examples/bzlmod/other_module/other_module/pkg/BUILD.bazel16
-rw-r--r--examples/bzlmod/other_module/other_module/pkg/bin.py6
-rw-r--r--examples/bzlmod/other_module/requirements.in1
-rw-r--r--examples/bzlmod/other_module/requirements_lock_3_11.txt10
-rw-r--r--examples/bzlmod/patches/BUILD.bazel4
-rw-r--r--examples/bzlmod/patches/empty.patch (renamed from examples/py_proto_library/WORKSPACE.bzlmod)0
-rw-r--r--examples/bzlmod/patches/requests_metadata.patch12
-rw-r--r--examples/bzlmod/patches/requests_record.patch11
-rw-r--r--examples/bzlmod/py_proto_library/BUILD.bazel18
-rw-r--r--examples/bzlmod/py_proto_library/example.com/another_proto/BUILD.bazel16
-rw-r--r--examples/bzlmod/py_proto_library/example.com/another_proto/message.proto10
-rw-r--r--examples/bzlmod/py_proto_library/example.com/proto/BUILD.bazel17
-rw-r--r--examples/bzlmod/py_proto_library/example.com/proto/pricetag.proto (renamed from examples/py_proto_library/pricetag.proto)3
-rw-r--r--examples/bzlmod/py_proto_library/message_test.py16
-rw-r--r--examples/bzlmod/py_proto_library/test.py21
-rw-r--r--examples/bzlmod/requirements.in6
-rw-r--r--examples/bzlmod/requirements_lock_3_10.txt152
-rw-r--r--examples/bzlmod/requirements_lock_3_9.txt170
-rw-r--r--examples/bzlmod/requirements_windows_3_10.txt153
-rw-r--r--examples/bzlmod/requirements_windows_3_9.txt171
-rw-r--r--examples/bzlmod/test.py2
-rw-r--r--examples/bzlmod/tests/dupe_requirements/BUILD.bazel19
-rw-r--r--examples/bzlmod/tests/dupe_requirements/dupe_requirements_test.py4
-rw-r--r--examples/bzlmod/tests/dupe_requirements/requirements.in2
-rw-r--r--examples/bzlmod/tests/dupe_requirements/requirements.txt97
-rw-r--r--examples/bzlmod/tests/other_module/BUILD.bazel14
-rw-r--r--examples/bzlmod/whl_mods/BUILD.bazel4
-rw-r--r--examples/bzlmod/whl_mods/appended_build_content.BUILD9
-rw-r--r--examples/bzlmod/whl_mods/pip_whl_mods_test.py99
-rw-r--r--examples/bzlmod_build_file_generation/BUILD.bazel9
-rw-r--r--examples/bzlmod_build_file_generation/__test__.py2
-rw-r--r--examples/bzlmod_build_file_generation/gazelle_python.yaml4
-rw-r--r--examples/bzlmod_build_file_generation/requirements_lock.txt10
-rw-r--r--examples/bzlmod_build_file_generation/requirements_windows.txt10
-rw-r--r--examples/multi_python_versions/MODULE.bazel57
-rw-r--r--examples/multi_python_versions/WORKSPACE.bzlmod (renamed from tests/compile_pip_requirements_test_from_external_workspace/BUILD.bazel)0
-rw-r--r--examples/multi_python_versions/requirements/BUILD.bazel12
-rw-r--r--examples/multi_python_versions/requirements/requirements_lock_3_10.txt120
-rw-r--r--examples/multi_python_versions/requirements/requirements_lock_3_11.txt120
-rw-r--r--examples/multi_python_versions/requirements/requirements_lock_3_8.txt120
-rw-r--r--examples/multi_python_versions/requirements/requirements_lock_3_9.txt120
-rw-r--r--examples/multi_python_versions/tests/my_lib_test.py7
-rw-r--r--examples/pip_install/.bazelrc2
-rw-r--r--examples/pip_install/BUILD.bazel111
-rw-r--r--examples/pip_install/README.md4
-rw-r--r--examples/pip_install/WORKSPACE96
-rw-r--r--examples/pip_install/pip_install_test.py80
-rw-r--r--examples/pip_install/requirements.in4
-rw-r--r--examples/pip_install/requirements.txt110
-rw-r--r--examples/pip_install/requirements_windows.txt106
-rw-r--r--examples/pip_parse/BUILD.bazel29
-rw-r--r--examples/pip_parse/MODULE.bazel31
-rw-r--r--examples/pip_parse/WORKSPACE14
-rw-r--r--examples/pip_parse/WORKSPACE.bzlmod0
-rw-r--r--examples/pip_parse/pip_parse_test.py56
-rw-r--r--examples/pip_parse/requirements.in4
-rw-r--r--examples/pip_parse/requirements_lock.txt163
-rw-r--r--examples/pip_parse/requirements_windows.txt242
-rw-r--r--examples/pip_parse_vendored/.bazelrc4
-rw-r--r--examples/pip_parse_vendored/BUILD.bazel7
-rw-r--r--examples/pip_parse_vendored/requirements.bzl56
-rw-r--r--examples/pip_parse_vendored/requirements.in1
-rw-r--r--examples/pip_parse_vendored/requirements.txt10
-rw-r--r--examples/pip_repository_annotations/.bazelrc4
-rw-r--r--examples/pip_repository_annotations/BUILD.bazel26
-rw-r--r--examples/pip_repository_annotations/WORKSPACE20
-rw-r--r--examples/pip_repository_annotations/requirements.in3
-rw-r--r--examples/pip_repository_annotations/requirements.txt18
-rw-r--r--examples/py_proto_library/.bazelrc2
-rw-r--r--examples/py_proto_library/BUILD.bazel22
-rw-r--r--examples/py_proto_library/MODULE.bazel23
-rw-r--r--examples/py_proto_library/example.com/another_proto/BUILD.bazel16
-rw-r--r--examples/py_proto_library/example.com/another_proto/message.proto10
-rw-r--r--examples/py_proto_library/example.com/proto/BUILD.bazel17
-rw-r--r--examples/py_proto_library/example.com/proto/pricetag.proto11
-rw-r--r--examples/py_proto_library/message_test.py15
-rw-r--r--examples/py_proto_library/test.py8
-rw-r--r--examples/wheel/BUILD.bazel44
-rw-r--r--examples/wheel/wheel_test.py197
-rw-r--r--gazelle/.bazelrc8
-rw-r--r--gazelle/BUILD.bazel13
-rw-r--r--gazelle/MODULE.bazel4
-rw-r--r--gazelle/README.md63
-rw-r--r--gazelle/WORKSPACE14
-rw-r--r--gazelle/def.bzl2
-rw-r--r--gazelle/go.mod2
-rw-r--r--gazelle/go.sum4
-rw-r--r--gazelle/manifest/defs.bzl37
-rw-r--r--gazelle/manifest/generate/generate.go22
-rw-r--r--gazelle/manifest/manifest.go8
-rw-r--r--gazelle/modules_mapping/BUILD.bazel2
-rw-r--r--gazelle/modules_mapping/def.bzl8
-rw-r--r--gazelle/python/BUILD.bazel65
-rw-r--r--gazelle/python/__main__.py32
-rw-r--r--gazelle/python/configure.go12
-rw-r--r--gazelle/python/gazelle_test.bzl49
-rw-r--r--gazelle/python/generate.go189
-rw-r--r--gazelle/python/kinds.go3
-rw-r--r--gazelle/python/lifecycle.go26
-rw-r--r--gazelle/python/parse.py31
-rw-r--r--gazelle/python/parse_test.py39
-rw-r--r--gazelle/python/parser.go59
-rw-r--r--gazelle/python/python_test.go6
-rw-r--r--gazelle/python/resolve.go24
-rw-r--r--gazelle/python/std_modules.go37
-rw-r--r--gazelle/python/target.go5
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/BUILD.in8
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/BUILD.out47
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/README.md4
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/WORKSPACE1
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/__init__.py15
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/collided_main.py4
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/main.py5
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/main2.py4
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/main_test.py7
-rw-r--r--gazelle/python/testdata/binary_without_entrypoint/test.yaml18
-rw-r--r--gazelle/python/testdata/dependency_resolution_order/BUILD.out2
-rw-r--r--gazelle/python/testdata/dependency_resolution_order/bar/BUILD.out1
-rw-r--r--gazelle/python/testdata/dependency_resolution_order/baz/BUILD.out1
-rw-r--r--gazelle/python/testdata/dependency_resolution_order/foo/BUILD.out1
-rw-r--r--gazelle/python/testdata/dependency_resolution_order/somewhere/bar/BUILD.out1
-rw-r--r--gazelle/python/testdata/dont_rename_target/BUILD.in1
-rw-r--r--gazelle/python/testdata/file_name_matches_import_statement/BUILD.out2
-rw-r--r--gazelle/python/testdata/first_party_file_and_directory_modules/foo/BUILD.out1
-rw-r--r--gazelle/python/testdata/first_party_file_and_directory_modules/one/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/foo/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/import_from_init_py/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/import_from_multiple/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/import_nested_file/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/import_nested_module/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/import_nested_var/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/import_top_level_var/BUILD.out1
-rw-r--r--gazelle/python/testdata/from_imports/std_module/BUILD.out1
-rw-r--r--gazelle/python/testdata/ignored_invalid_imported_module/BUILD.out2
-rw-r--r--gazelle/python/testdata/monorepo/coarse_grained/BUILD.out13
-rw-r--r--gazelle/python/testdata/monorepo/coarse_grained/bar/bar_test.py0
-rw-r--r--gazelle/python/testdata/monorepo/coarse_grained/foo/bar/bar_test.py0
-rw-r--r--gazelle/python/testdata/monorepo/one/BUILD.out2
-rw-r--r--gazelle/python/testdata/monorepo/one/bar/BUILD.out2
-rw-r--r--gazelle/python/testdata/monorepo/three/BUILD.out4
-rw-r--r--gazelle/python/testdata/monorepo/two/BUILD.out2
-rw-r--r--gazelle/python/testdata/naming_convention/dont_rename/BUILD.out3
-rw-r--r--gazelle/python/testdata/naming_convention/resolve_conflict/BUILD.out3
-rw-r--r--gazelle/python/testdata/per_file/BUILD.in11
-rw-r--r--gazelle/python/testdata/per_file/BUILD.out34
-rw-r--r--gazelle/python/testdata/per_file/README.md5
-rw-r--r--gazelle/python/testdata/per_file/WORKSPACE1
-rw-r--r--gazelle/python/testdata/per_file/__init__.py0
-rw-r--r--gazelle/python/testdata/per_file/bar.py15
-rw-r--r--gazelle/python/testdata/per_file/bar_test.py0
-rw-r--r--gazelle/python/testdata/per_file/baz.py15
-rw-r--r--gazelle/python/testdata/per_file/foo.py15
-rw-r--r--gazelle/python/testdata/per_file/foo_test.py0
-rw-r--r--gazelle/python/testdata/per_file/test.yaml15
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/BUILD.in4
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/BUILD.out20
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/README.md3
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/WORKSPACE1
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/__init__.py15
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/foo.py15
-rw-r--r--gazelle/python/testdata/per_file_non_empty_init/test.yaml15
-rw-r--r--gazelle/python/testdata/per_file_subdirs/BUILD.in3
-rw-r--r--gazelle/python/testdata/per_file_subdirs/BUILD.out10
-rw-r--r--gazelle/python/testdata/per_file_subdirs/README.md3
-rw-r--r--gazelle/python/testdata/per_file_subdirs/WORKSPACE1
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/BUILD.in1
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/BUILD.out45
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/__init__.py15
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/__test__.py0
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/bar.py0
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/bar_test.py0
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/foo.py16
-rw-r--r--gazelle/python/testdata/per_file_subdirs/bar/foo_test.py0
-rw-r--r--gazelle/python/testdata/per_file_subdirs/baz/baz.py15
-rw-r--r--gazelle/python/testdata/per_file_subdirs/foo.py15
-rw-r--r--gazelle/python/testdata/per_file_subdirs/test.yaml15
-rw-r--r--gazelle/python/testdata/per_file_subdirs/test_target/BUILD.in3
-rw-r--r--gazelle/python/testdata/per_file_subdirs/test_target/BUILD.out25
-rw-r--r--gazelle/python/testdata/per_file_subdirs/test_target/a_test.py0
-rw-r--r--gazelle/python/testdata/per_file_subdirs/test_target/b_test.py0
-rw-r--r--gazelle/python/testdata/python_ignore_dependencies_directive/BUILD.out2
-rw-r--r--gazelle/python/testdata/python_ignore_files_directive/bar/BUILD.out1
-rw-r--r--gazelle/python/testdata/python_target_with_test_in_name/BUILD.out2
-rw-r--r--gazelle/python/testdata/relative_imports/BUILD.in1
-rw-r--r--gazelle/python/testdata/relative_imports/BUILD.out2
-rw-r--r--gazelle/python/testdata/relative_imports/package2/BUILD.out2
-rw-r--r--gazelle/python/testdata/relative_imports/package2/module3.py1
-rw-r--r--gazelle/python/testdata/sibling_imports/pkg/BUILD.out3
-rw-r--r--gazelle/python/testdata/simple_library_without_init/foo/BUILD.out1
-rw-r--r--gazelle/python/testdata/simple_test_with_conftest/bar/BUILD.out3
-rw-r--r--gazelle/python/testdata/subdir_sources/foo/BUILD.out1
-rw-r--r--gazelle/python/testdata/subdir_sources/foo/has_build/BUILD.out1
-rw-r--r--gazelle/python/testdata/subdir_sources/foo/has_init/BUILD.out1
-rw-r--r--gazelle/python/testdata/subdir_sources/foo/has_main/BUILD.out2
-rw-r--r--gazelle/python/testdata/subdir_sources/foo/has_test/BUILD.out2
-rw-r--r--gazelle/python/testdata/subdir_sources/one/BUILD.out1
-rw-r--r--gazelle/python/testdata/subdir_sources/one/two/BUILD.out1
-rw-r--r--gazelle/python/testdata/with_nested_import_statements/BUILD.out2
-rw-r--r--gazelle/python/testdata/with_third_party_requirements/BUILD.out8
-rw-r--r--gazelle/python/testdata/with_third_party_requirements_from_imports/BUILD.out6
-rw-r--r--gazelle/pythonconfig/BUILD.bazel2
-rw-r--r--gazelle/pythonconfig/pythonconfig.go110
-rw-r--r--gazelle/pythonconfig/pythonconfig_test.go4
-rw-r--r--internal_deps.bzl151
-rw-r--r--internal_setup.bzl14
-rw-r--r--python/BUILD.bazel95
-rw-r--r--python/config_settings/BUILD.bazel1
-rw-r--r--python/config_settings/private/BUILD.bazel7
-rw-r--r--python/config_settings/transition.bzl47
-rw-r--r--python/defs.bzl6
-rw-r--r--python/entry_points/BUILD.bazel41
-rw-r--r--python/entry_points/py_console_script_binary.bzl24
-rw-r--r--python/extensions/BUILD.bazel18
-rw-r--r--python/extensions/pip.bzl482
-rw-r--r--python/extensions/python.bzl243
-rw-r--r--python/packaging.bzl11
-rw-r--r--python/pip.bzl233
-rw-r--r--python/pip_install/BUILD.bazel84
-rw-r--r--python/pip_install/pip_hub_repository_requirements_bzlmod.bzl.tmpl35
-rw-r--r--python/pip_install/pip_repository.bzl622
-rw-r--r--python/pip_install/pip_repository_requirements.bzl.tmpl47
-rw-r--r--python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl33
-rw-r--r--python/pip_install/private/BUILD.bazel24
-rw-r--r--python/pip_install/private/generate_group_library_build_bazel.bzl105
-rw-r--r--python/pip_install/private/generate_whl_library_build_bazel.bzl344
-rw-r--r--python/pip_install/private/srcs.bzl7
-rw-r--r--python/pip_install/repositories.bzl72
-rw-r--r--python/pip_install/requirements.bzl41
-rw-r--r--python/pip_install/tools/dependency_resolver/dependency_resolver.py55
-rw-r--r--python/pip_install/tools/lib/BUILD.bazel82
-rw-r--r--python/pip_install/tools/lib/annotation.py129
-rw-r--r--python/pip_install/tools/lib/annotations_test.py121
-rw-r--r--python/pip_install/tools/lib/annotations_test_helpers.bzl47
-rw-r--r--python/pip_install/tools/lib/bazel.py45
-rwxr-xr-xpython/pip_install/tools/requirements.txt14
-rw-r--r--python/pip_install/tools/wheel_installer/BUILD.bazel27
-rw-r--r--python/pip_install/tools/wheel_installer/arguments.py (renamed from python/pip_install/tools/lib/arguments.py)50
-rw-r--r--python/pip_install/tools/wheel_installer/arguments_test.py (renamed from python/pip_install/tools/lib/arguments_test.py)27
-rw-r--r--python/pip_install/tools/wheel_installer/wheel.py383
-rw-r--r--python/pip_install/tools/wheel_installer/wheel_installer.py329
-rw-r--r--python/pip_install/tools/wheel_installer/wheel_installer_test.py84
-rw-r--r--python/pip_install/tools/wheel_installer/wheel_test.py220
-rw-r--r--python/private/BUILD.bazel242
-rw-r--r--python/private/auth.bzl42
-rw-r--r--python/private/autodetecting_toolchain.bzl70
-rw-r--r--python/private/autodetecting_toolchain_interpreter.sh57
-rw-r--r--python/private/bzlmod/BUILD.bazel78
-rw-r--r--python/private/bzlmod/internal_deps.bzl (renamed from python/extensions/private/internal_deps.bzl)4
-rw-r--r--python/private/bzlmod/pip.bzl558
-rw-r--r--python/private/bzlmod/pip_repository.bzl87
-rw-r--r--python/private/bzlmod/python.bzl282
-rw-r--r--python/private/bzlmod/pythons_hub.bzl (renamed from python/extensions/private/pythons_hub.bzl)33
-rw-r--r--python/private/bzlmod/requirements.bzl.tmpl46
-rw-r--r--python/private/common/BUILD.bazel207
-rw-r--r--python/private/common/attributes.bzl245
-rw-r--r--python/private/common/attributes_bazel.bzl30
-rw-r--r--python/private/common/cc_helper.bzl23
-rw-r--r--python/private/common/common.bzl537
-rw-r--r--python/private/common/common_bazel.bzl109
-rw-r--r--python/private/common/providers.bzl224
-rw-r--r--python/private/common/py_binary_macro_bazel.bzl21
-rw-r--r--python/private/common/py_binary_rule_bazel.bzl52
-rw-r--r--python/private/common/py_executable.bzl860
-rw-r--r--python/private/common/py_executable_bazel.bzl483
-rw-r--r--python/private/common/py_internal.bzl26
-rw-r--r--python/private/common/py_library.bzl102
-rw-r--r--python/private/common/py_library_macro_bazel.bzl (renamed from python/extensions/private/BUILD.bazel)12
-rw-r--r--python/private/common/py_library_rule_bazel.bzl47
-rw-r--r--python/private/common/py_runtime_macro.bzl22
-rw-r--r--python/private/common/py_runtime_rule.bzl260
-rw-r--r--python/private/common/py_test_macro_bazel.bzl21
-rw-r--r--python/private/common/py_test_rule_bazel.bzl55
-rw-r--r--python/private/common/semantics.bzl31
-rw-r--r--python/private/coverage_deps.bzl7
-rw-r--r--python/private/full_version.bzl43
-rw-r--r--python/private/internal_config_repo.bzl99
-rw-r--r--python/private/labels.bzl24
-rw-r--r--python/private/parse_whl_name.bzl72
-rw-r--r--python/private/patch_whl.bzl119
-rw-r--r--python/private/proto/py_proto_library.bzl19
-rw-r--r--python/private/py_cc_toolchain_info.bzl2
-rw-r--r--python/private/py_console_script_binary.bzl87
-rw-r--r--python/private/py_console_script_gen.bzl93
-rw-r--r--python/private/py_console_script_gen.py180
-rw-r--r--python/private/py_runtime_pair_macro.bzl27
-rw-r--r--python/private/py_runtime_pair_rule.bzl151
-rw-r--r--python/private/py_wheel.bzl91
-rw-r--r--python/private/py_wheel_normalize_pep440.bzl519
-rw-r--r--python/private/python_bootstrap_template.txt559
-rw-r--r--python/private/reexports.bzl25
-rw-r--r--python/private/register_extension_info.bzl18
-rw-r--r--python/private/render_pkg_aliases.bzl190
-rw-r--r--python/private/repack_whl.py182
-rw-r--r--python/private/text_util.bzl89
-rw-r--r--python/private/toolchains_repo.bzl48
-rw-r--r--python/private/util.bzl6
-rw-r--r--python/private/which.bzl32
-rw-r--r--python/private/whl_target_platforms.bzl80
-rw-r--r--python/proto/BUILD.bazel18
-rw-r--r--python/py_binary.bzl14
-rw-r--r--python/py_cc_link_params_info.bzl5
-rw-r--r--python/py_info.bzl6
-rw-r--r--python/py_library.bzl14
-rw-r--r--python/py_runtime.bzl9
-rw-r--r--python/py_runtime_info.bzl6
-rw-r--r--python/py_runtime_pair.bzl9
-rw-r--r--python/py_test.bzl13
-rw-r--r--python/repositories.bzl72
-rw-r--r--python/runfiles/BUILD.bazel2
-rw-r--r--python/runfiles/py.typed0
-rw-r--r--python/runfiles/runfiles.py268
-rw-r--r--python/versions.bzl146
-rw-r--r--sphinxdocs/BUILD.bazel50
-rw-r--r--sphinxdocs/private/BUILD.bazel99
-rw-r--r--sphinxdocs/private/inventory_builder.py24
-rw-r--r--sphinxdocs/private/proto_to_markdown.py488
-rw-r--r--sphinxdocs/private/readthedocs.bzl48
-rw-r--r--sphinxdocs/private/readthedocs_install.py27
-rw-r--r--sphinxdocs/private/sphinx.bzl336
-rw-r--r--sphinxdocs/private/sphinx_build.py8
-rw-r--r--sphinxdocs/private/sphinx_server.py49
-rw-r--r--sphinxdocs/private/sphinx_stardoc.bzl139
-rw-r--r--sphinxdocs/readthedocs.bzl (renamed from tools/build_defs/python/tests/BUILD.bazel)15
-rw-r--r--sphinxdocs/sphinx.bzl37
-rw-r--r--sphinxdocs/sphinx_stardoc.bzl (renamed from examples/pip_install/test.py)13
-rw-r--r--sphinxdocs/tests/BUILD.bazel (renamed from python/pip_install/tools/lib/__init__.py)1
-rw-r--r--sphinxdocs/tests/proto_to_markdown/BUILD.bazel24
-rw-r--r--sphinxdocs/tests/proto_to_markdown/proto_to_markdown_test.py203
-rw-r--r--tests/BUILD.bazel9
-rw-r--r--tests/base_rules/BUILD.bazel13
-rw-r--r--tests/base_rules/base_tests.bzl (renamed from tools/build_defs/python/tests/base_tests.bzl)86
-rw-r--r--tests/base_rules/py_binary/BUILD.bazel (renamed from tools/build_defs/python/tests/py_binary/BUILD.bazel)0
-rw-r--r--tests/base_rules/py_binary/py_binary_tests.bzl (renamed from tools/build_defs/python/tests/py_binary/py_binary_tests.bzl)2
-rw-r--r--tests/base_rules/py_executable_base_tests.bzl (renamed from tools/build_defs/python/tests/py_executable_base_tests.bzl)47
-rw-r--r--tests/base_rules/py_info_subject.bzl (renamed from tools/build_defs/python/tests/py_info_subject.bzl)2
-rw-r--r--tests/base_rules/py_library/BUILD.bazel (renamed from tools/build_defs/python/tests/py_library/BUILD.bazel)0
-rw-r--r--tests/base_rules/py_library/py_library_tests.bzl (renamed from tools/build_defs/python/tests/py_library/py_library_tests.bzl)4
-rw-r--r--tests/base_rules/py_test/BUILD.bazel (renamed from tools/build_defs/python/tests/py_test/BUILD.bazel)0
-rw-r--r--tests/base_rules/py_test/py_test_tests.bzl (renamed from tools/build_defs/python/tests/py_test/py_test_tests.bzl)15
-rw-r--r--tests/base_rules/util.bzl (renamed from tools/build_defs/python/tests/util.bzl)5
-rw-r--r--tests/cc/BUILD.bazel29
-rw-r--r--tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl12
-rw-r--r--tests/config_settings/transition/BUILD.bazel3
-rw-r--r--tests/config_settings/transition/multi_version_tests.bzl68
-rw-r--r--tests/entry_points/BUILD.bazel39
-rw-r--r--tests/entry_points/py_console_script_gen_test.py197
-rw-r--r--tests/entry_points/simple_macro.bzl31
-rw-r--r--tests/integration/BUILD.bazel103
-rwxr-xr-xtests/integration/bazel_from_env6
-rw-r--r--tests/integration/compile_pip_requirements/.bazelignore4
-rw-r--r--tests/integration/compile_pip_requirements/.bazelrc (renamed from tests/compile_pip_requirements/.bazelrc)0
-rw-r--r--tests/integration/compile_pip_requirements/.gitignore (renamed from tests/compile_pip_requirements/.gitignore)0
-rw-r--r--tests/integration/compile_pip_requirements/BUILD.bazel (renamed from tests/compile_pip_requirements/BUILD.bazel)18
-rw-r--r--tests/integration/compile_pip_requirements/MODULE.bazel12
-rw-r--r--tests/integration/compile_pip_requirements/README.md (renamed from tests/compile_pip_requirements/README.md)0
-rw-r--r--tests/integration/compile_pip_requirements/WORKSPACE (renamed from tests/compile_pip_requirements/WORKSPACE)2
-rw-r--r--tests/integration/compile_pip_requirements/WORKSPACE.bzlmod0
-rw-r--r--tests/integration/compile_pip_requirements/requirements.txt (renamed from tests/compile_pip_requirements/requirements.txt)0
-rw-r--r--tests/integration/compile_pip_requirements/requirements_lock.txt (renamed from tests/compile_pip_requirements/requirements_lock.txt)2
-rw-r--r--tests/integration/compile_pip_requirements/requirements_lock_darwin.txt (renamed from tests/compile_pip_requirements/requirements_lock_darwin.txt)2
-rw-r--r--tests/integration/compile_pip_requirements/requirements_lock_linux.txt (renamed from tests/compile_pip_requirements/requirements_lock_linux.txt)2
-rw-r--r--tests/integration/compile_pip_requirements/requirements_lock_windows.txt (renamed from tests/compile_pip_requirements/requirements_lock_windows.txt)2
-rw-r--r--tests/integration/compile_pip_requirements/requirements_nohashes_lock.txt (renamed from tests/compile_pip_requirements/requirements_nohashes_lock.txt)2
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc (renamed from tests/compile_pip_requirements_test_from_external_workspace/.bazelrc)0
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/.gitignore (renamed from tests/compile_pip_requirements_test_from_external_workspace/.gitignore)0
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/BUILD.bazel0
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/MODULE.bazel25
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/README.md (renamed from tests/compile_pip_requirements_test_from_external_workspace/README.md)2
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE (renamed from tests/compile_pip_requirements_test_from_external_workspace/WORKSPACE)6
-rw-r--r--tests/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE.bzlmod0
-rw-r--r--tests/integration/ignore_root_user_error/.bazelrc (renamed from tests/ignore_root_user_error/.bazelrc)0
-rw-r--r--tests/integration/ignore_root_user_error/.gitignore (renamed from tests/ignore_root_user_error/.gitignore)0
-rw-r--r--tests/integration/ignore_root_user_error/BUILD.bazel (renamed from tests/ignore_root_user_error/BUILD.bazel)0
-rw-r--r--tests/integration/ignore_root_user_error/README.md (renamed from tests/ignore_root_user_error/README.md)0
-rw-r--r--tests/integration/ignore_root_user_error/WORKSPACE (renamed from tests/ignore_root_user_error/WORKSPACE)6
-rw-r--r--tests/integration/ignore_root_user_error/foo_test.py (renamed from tests/ignore_root_user_error/foo_test.py)0
-rw-r--r--tests/integration/integration_test.bzl96
-rw-r--r--tests/integration/pip_repository_entry_points/.bazelrc (renamed from tests/pip_repository_entry_points/.bazelrc)4
-rw-r--r--tests/integration/pip_repository_entry_points/.gitignore (renamed from examples/pip_install/.gitignore)0
-rw-r--r--tests/integration/pip_repository_entry_points/BUILD.bazel32
-rw-r--r--tests/integration/pip_repository_entry_points/WORKSPACE (renamed from tests/pip_repository_entry_points/WORKSPACE)24
-rw-r--r--tests/integration/pip_repository_entry_points/pip_repository_entry_points_test.py (renamed from tests/pip_repository_entry_points/pip_repository_entry_points_test.py)0
-rw-r--r--tests/integration/pip_repository_entry_points/requirements.in8
-rw-r--r--tests/integration/pip_repository_entry_points/requirements.txt (renamed from tests/pip_repository_entry_points/requirements.txt)26
-rw-r--r--tests/integration/pip_repository_entry_points/requirements_windows.txt (renamed from tests/pip_repository_entry_points/requirements_windows.txt)44
-rw-r--r--tests/integration/py_cc_toolchain_registered/.bazelrc2
-rw-r--r--tests/integration/py_cc_toolchain_registered/BUILD.bazel19
-rw-r--r--tests/integration/py_cc_toolchain_registered/MODULE.bazel7
-rw-r--r--tests/integration/py_cc_toolchain_registered/WORKSPACE13
-rw-r--r--tests/integration/py_cc_toolchain_registered/defs.bzl38
-rw-r--r--tests/pip_hub_repository/render_pkg_aliases/BUILD.bazel3
-rw-r--r--tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl338
-rw-r--r--tests/pip_install/BUILD.bazel0
-rw-r--r--tests/pip_install/group_library/BUILD.bazel3
-rw-r--r--tests/pip_install/group_library/generate_build_bazel_tests.bzl57
-rw-r--r--tests/pip_install/whl_library/BUILD.bazel3
-rw-r--r--tests/pip_install/whl_library/generate_build_bazel_tests.bzl397
-rw-r--r--tests/pip_repository_entry_points/.gitignore4
-rw-r--r--tests/pip_repository_entry_points/BUILD.bazel55
-rw-r--r--tests/pip_repository_entry_points/requirements.in5
-rw-r--r--tests/private/parse_whl_name/BUILD.bazel3
-rw-r--r--tests/private/parse_whl_name/parse_whl_name_tests.bzl72
-rw-r--r--tests/private/text_util/BUILD.bazel (renamed from examples/pip_install/main.py)10
-rw-r--r--tests/private/text_util/render_tests.bzl63
-rw-r--r--tests/private/whl_target_platforms/BUILD.bazel17
-rw-r--r--tests/private/whl_target_platforms/whl_target_platforms_tests.bzl54
-rw-r--r--tests/py_runtime/BUILD.bazel17
-rw-r--r--tests/py_runtime/py_runtime_tests.bzl420
-rw-r--r--tests/py_runtime_info_subject.bzl102
-rw-r--r--tests/py_runtime_pair/BUILD.bazel17
-rw-r--r--tests/py_runtime_pair/py_runtime_pair_tests.bzl147
-rw-r--r--tests/py_wheel/py_wheel/BUILD.bazel (renamed from tools/build_defs/python/tests/py_wheel/BUILD.bazel)0
-rw-r--r--tests/py_wheel/py_wheel/py_wheel_tests.bzl (renamed from tools/build_defs/python/tests/py_wheel/py_wheel_tests.bzl)2
-rw-r--r--tests/py_wheel/py_wheel_tests.bzl103
-rw-r--r--tests/pycross/0001-Add-new-file-for-testing-patch-support.patch17
-rw-r--r--tests/pycross/BUILD.bazel64
-rw-r--r--tests/pycross/patched_py_wheel_library_test.py38
-rw-r--r--tests/pycross/py_wheel_library_test.py46
-rw-r--r--tests/runfiles/BUILD.bazel6
-rw-r--r--tests/runfiles/runfiles_test.py94
-rw-r--r--tests/support/BUILD.bazel39
-rw-r--r--tests/support/test_platforms.bzl20
-rw-r--r--tests/toolchains/BUILD.bazel (renamed from python/tests/toolchains/BUILD.bazel)0
-rw-r--r--tests/toolchains/defs.bzl (renamed from python/tests/toolchains/defs.bzl)55
-rw-r--r--tests/toolchains/run_acceptance_test.py.tmpl (renamed from python/tests/toolchains/run_acceptance_test.py.tmpl)52
-rw-r--r--tests/toolchains/versions_test.bzl (renamed from python/tests/toolchains/versions_test.bzl)0
-rw-r--r--tests/toolchains/workspace_template/BUILD.bazel (renamed from python/tests/toolchains/workspace_template/BUILD.bazel)1
-rw-r--r--tests/toolchains/workspace_template/BUILD.bazel.tmpl (renamed from python/tests/toolchains/workspace_template/BUILD.bazel.tmpl)0
-rw-r--r--tests/toolchains/workspace_template/MODULE.bazel.tmpl19
-rw-r--r--tests/toolchains/workspace_template/README.md (renamed from python/tests/toolchains/workspace_template/README.md)0
-rw-r--r--tests/toolchains/workspace_template/WORKSPACE.tmpl (renamed from python/tests/toolchains/workspace_template/WORKSPACE.tmpl)4
-rw-r--r--tests/toolchains/workspace_template/python_version_test.py (renamed from python/tests/toolchains/workspace_template/python_version_test.py)0
-rw-r--r--third_party/rules_pycross/LICENSE201
-rw-r--r--third_party/rules_pycross/pycross/private/BUILD.bazel14
-rw-r--r--third_party/rules_pycross/pycross/private/providers.bzl32
-rw-r--r--third_party/rules_pycross/pycross/private/tools/BUILD.bazel26
-rw-r--r--third_party/rules_pycross/pycross/private/tools/wheel_installer.py196
-rw-r--r--third_party/rules_pycross/pycross/private/wheel_library.bzl174
-rw-r--r--tools/BUILD.bazel1
-rw-r--r--tools/bazel_integration_test/BUILD.bazel1
-rw-r--r--tools/bazel_integration_test/bazel_integration_test.bzl134
-rw-r--r--tools/bazel_integration_test/test_runner.py111
-rw-r--r--tools/build_defs/python/private/BUILD.bazel27
-rw-r--r--tools/build_defs/python/private/py_internal_renamed.bzl30
-rw-r--r--tools/private/update_deps/BUILD.bazel76
-rw-r--r--tools/private/update_deps/args.py35
-rwxr-xr-xtools/private/update_deps/update_coverage_deps.py (renamed from tools/update_coverage_deps.py)80
-rw-r--r--tools/private/update_deps/update_file.py114
-rw-r--r--tools/private/update_deps/update_file_test.py128
-rwxr-xr-xtools/private/update_deps/update_pip_deps.py169
-rw-r--r--tools/publish/BUILD.bazel1
-rw-r--r--tools/publish/requirements_darwin.txt6
-rw-r--r--tools/publish/requirements_windows.txt6
-rwxr-xr-xtools/update_deleted_packages.sh (renamed from tools/bazel_integration_test/update_deleted_packages.sh)2
-rw-r--r--tools/wheelmaker.py340
-rw-r--r--version.bzl12
525 files changed, 27845 insertions, 7003 deletions
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index 1da4d9f..8649797 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -21,9 +21,8 @@ buildifier:
.minimum_supported_version: &minimum_supported_version
# For testing minimum supported version.
# NOTE: Keep in sync with //:version.bzl
- bazel: 5.4.0
-.minimum_supported_bzlmod_version: &minimum_supported_bzlmod_version
- bazel: 6.0.0 # test minimum supported version of bazel for bzlmod tests
+ bazel: 6.4.0
+ skip_in_bazel_downstream_pipeline: "Bazel 6 required"
.reusable_config: &reusable_config
build_targets:
- "--"
@@ -33,16 +32,29 @@ buildifier:
- "@rules_python//examples/wheel/..."
build_flags:
- "--keep_going"
+ - "--build_tag_filters=-integration-test"
test_targets:
- "--"
- "..."
test_flags:
- "--test_tag_filters=-integration-test"
-.common_bzlmod_flags: &common_bzlmod_flags
+.common_workspace_flags: &common_workspace_flags
test_flags:
- - "--experimental_enable_bzlmod"
+ - "--noenable_bzlmod"
build_flags:
- - "--experimental_enable_bzlmod"
+ - "--noenable_bzlmod"
+.common_bazelinbazel_config: &common_bazelinbazel_config
+ build_flags:
+ - "--build_tag_filters=integration-test"
+ test_flags:
+ - "--test_tag_filters=integration-test"
+ - "--jobs=2"
+ # The integration tests are so expensive that only a few can be run concurrently
+ # without harming overall reliability and runtime.
+ - "--local_test_jobs=2"
+ build_targets: ["..."]
+ test_targets: ["..."]
+
.reusable_build_test_all: &reusable_build_test_all
build_targets: ["..."]
test_targets: ["..."]
@@ -62,56 +74,93 @@ buildifier:
- //tests:version_3_8_test
- //tests:version_3_9_test
- //tests:version_default_test
+.pystar_base: &pystar_base
+ bazel: "7.x"
+ environment:
+ RULES_PYTHON_ENABLE_PYSTAR: "1"
+ test_flags:
+ # The doc check tests fail because the Starlark implementation makes the
+ # PyInfo and PyRuntimeInfo symbols become documented.
+ - "--test_tag_filters=-integration-test,-doc_check_test"
tasks:
gazelle_extension_min:
+ <<: *common_workspace_flags
<<: *minimum_supported_version
- name: Test the Gazelle extension using minimum supported Bazel version
+ name: "Gazelle: workspace, minumum supported Bazel version"
platform: ubuntu2004
build_targets: ["//..."]
test_targets: ["//..."]
working_directory: gazelle
- gazelle_extension:
- name: Test the Gazelle extension
+ gazelle_extension_workspace:
+ <<: *common_workspace_flags
+ name: "Gazelle: workspace"
platform: ubuntu2004
build_targets: ["//..."]
test_targets: ["//..."]
working_directory: gazelle
- gazelle_extension_bzlmod:
- <<: *common_bzlmod_flags
- name: Test the Gazelle extension under bzlmod
+ gazelle_extension:
+ name: "Gazelle: default settings"
platform: ubuntu2004
build_targets: ["//..."]
test_targets: ["//..."]
working_directory: gazelle
- ubuntu_min:
+ ubuntu_min_workspace:
<<: *minimum_supported_version
<<: *reusable_config
- name: Default test on Ubuntu using minimum supported Bazel version
+ <<: *common_workspace_flags
+ name: "Default: Ubuntu, workspace, minimum Bazel"
+ platform: ubuntu2004
+ ubuntu_min_bzlmod:
+ <<: *minimum_supported_version
+ <<: *reusable_config
+ name: "Default: Ubuntu, bzlmod, minimum Bazel"
platform: ubuntu2004
ubuntu:
<<: *reusable_config
- name: Default test on Ubuntu
+ name: "Default: Ubuntu"
+ platform: ubuntu2004
+
+ pystar_ubuntu_workspace:
+ <<: *reusable_config
+ <<: *pystar_base
+ name: "Default test: Ubuntu, Pystar, workspace"
+ platform: ubuntu2004
+ pystar_ubuntu_bzlmod:
+ <<: *reusable_config
+ <<: *pystar_base
+ name: "Default test: Ubuntu, Pystar, bzlmod"
platform: ubuntu2004
+ pystar_mac_workspace:
+ <<: *reusable_config
+ <<: *common_workspace_flags
+ <<: *pystar_base
+ name: "Default test: Mac, Pystar, workspace"
+ platform: macos
+ pystar_windows_workspace:
+ <<: *reusable_config
+ <<: *pystar_base
+ name: "Default test: Windows, Pystar, workspace"
+ platform: windows
+
debian:
<<: *reusable_config
- name: Default test on Debian
+ name: "Default: Debian"
platform: debian11
macos:
<<: *reusable_config
- name: Default test on macOS
+ name: "Default: MacOS"
platform: macos
windows:
<<: *reusable_config
- name: Default test on Windows
+ name: "Default: Windows"
platform: windows
test_flags:
- "--test_tag_filters=-integration-test,-fix-windows"
-
rbe_min:
<<: *minimum_supported_version
<<: *reusable_config
- name: Test on RBE using minimum supported Bazel version
+ name: "RBE: Ubuntu, minimum Bazel"
platform: rbe_ubuntu1604
build_flags:
# BazelCI sets --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1,
@@ -119,8 +168,9 @@ tasks:
# on Bazel 5.4 and earlier. To workaround this, manually specify the
# build kite cc toolchain.
- "--extra_toolchains=@buildkite_config//config:cc-toolchain"
+ - "--build_tag_filters=-docs"
test_flags:
- - "--test_tag_filters=-integration-test,-acceptance-test"
+ - "--test_tag_filters=-integration-test,-acceptance-test,-docs"
# BazelCI sets --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1,
# which prevents cc toolchain autodetection from working correctly
# on Bazel 5.4 and earlier. To workaround this, manually specify the
@@ -128,86 +178,91 @@ tasks:
- "--extra_toolchains=@buildkite_config//config:cc-toolchain"
rbe:
<<: *reusable_config
- name: Test on RBE
+ name: "RBE: Ubuntu"
platform: rbe_ubuntu1604
test_flags:
- "--test_tag_filters=-integration-test,-acceptance-test"
- integration_test_build_file_generation_ubuntu_minimum_supported:
+ integration_test_build_file_generation_ubuntu_minimum_supported_workspace:
<<: *minimum_supported_version
<<: *reusable_build_test_all
- name: build_file_generation integration tests on Ubuntu using minimum supported Bazel version
+ <<: *common_workspace_flags
+ name: "examples/build_file_generation: Ubuntu, workspace, minimum Bazel"
working_directory: examples/build_file_generation
platform: ubuntu2004
- integration_test_build_file_generation_ubuntu:
+ integration_test_build_file_generation_ubuntu_workspace:
<<: *reusable_build_test_all
- name: build_file_generation integration tests on Ubuntu
+ <<: *common_workspace_flags
+ name: "examples/build_file_generation: Ubuntu, workspace"
working_directory: examples/build_file_generation
platform: ubuntu2004
- integration_test_build_file_generation_debian:
+ integration_test_build_file_generation_debian_workspace:
<<: *reusable_build_test_all
- name: build_file_generation integration tests on Debian
+ <<: *common_workspace_flags
+ name: "examples/build_file_generation: Debian, workspace"
working_directory: examples/build_file_generation
platform: debian11
- integration_test_build_file_generation_macos:
+ integration_test_build_file_generation_macos_workspace:
<<: *reusable_build_test_all
- name: build_file_generation integration tests on macOS
+ <<: *common_workspace_flags
+ name: "examples/build_file_generation: macOS, workspace"
working_directory: examples/build_file_generation
platform: macos
- integration_test_build_file_generation_windows:
+ integration_test_build_file_generation_windows_workspace:
<<: *reusable_build_test_all
- name: build_file_generation integration tests on Windows
+ <<: *common_workspace_flags
+ name: "examples/build_file_generation: Windows, workspace"
working_directory: examples/build_file_generation
platform: windows
integration_test_bzlmod_ubuntu_min:
- <<: *minimum_supported_bzlmod_version
+ <<: *minimum_supported_version
<<: *reusable_build_test_all
<<: *coverage_targets_example_bzlmod
- name: bzlmod integration tests on Ubuntu using minimum supported Bazel version
+ name: "examples/bzlmod: Ubuntu, minimum Bazel"
working_directory: examples/bzlmod
platform: ubuntu2004
integration_test_bzlmod_ubuntu:
<<: *reusable_build_test_all
<<: *coverage_targets_example_bzlmod
- name: bzlmod integration tests on Ubuntu
+ name: "examples/bzlmod: Ubuntu"
working_directory: examples/bzlmod
platform: ubuntu2004
integration_test_bzlmod_debian:
<<: *reusable_build_test_all
<<: *coverage_targets_example_bzlmod
- name: bzlmod integration tests on Debian
+ name: "examples/bzlmod: Debian"
working_directory: examples/bzlmod
platform: debian11
integration_test_bzlmod_macos:
<<: *reusable_build_test_all
<<: *coverage_targets_example_bzlmod
- name: bzlmod integration tests on macOS
+ name: "examples/bzlmod: macOS"
working_directory: examples/bzlmod
platform: macos
integration_test_bzlmod_windows:
<<: *reusable_build_test_all
# coverage is not supported on Windows
- name: bzlmod integration tests on Windows
+ name: "examples/bzlmod: Windows"
working_directory: examples/bzlmod
platform: windows
integration_test_bzlmod_generate_build_file_generation_ubuntu_min:
- <<: *minimum_supported_bzlmod_version
+ <<: *minimum_supported_version
<<: *reusable_build_test_all
<<: *coverage_targets_example_bzlmod_build_file_generation
- name: example bzlmod build file min bazel version integration test
+ name: "examples/bzlmod_build_file_generation: Ubuntu, minimum Bazel"
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
+ name: "examples/bzlmod_build_file_generation: Ubuntu"
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
+ name: "examples/bzlmod_build_file_generation: Ubuntu, Gazelle and pip"
working_directory: examples/bzlmod_build_file_generation
platform: ubuntu2004
shell_commands:
@@ -216,228 +271,181 @@ tasks:
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
+ name: "examples/bzlmod_build_file_integration: Debian"
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
+ name: "examples/bzlmod_build_file_generation: MacOS"
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
+ name: "examples/bzlmod_build_file_generateion: Windows"
working_directory: examples/bzlmod_build_file_generation
platform: windows
- integration_test_multi_python_versions_ubuntu_min:
- <<: *minimum_supported_version
- <<: *reusable_build_test_all
- name: multi_python_versions integration tests on Ubuntu using minimum supported Bazel version
- working_directory: examples/multi_python_versions
- platform: ubuntu2004
- integration_test_multi_python_versions_ubuntu:
+ integration_test_multi_python_versions_ubuntu_workspace:
<<: *reusable_build_test_all
+ <<: *common_workspace_flags
<<: *coverage_targets_example_multi_python
- name: multi_python_versions integration tests on Ubuntu
+ name: "examples/multi_python_versions: Ubuntu, workspace"
working_directory: examples/multi_python_versions
platform: ubuntu2004
- integration_test_multi_python_versions_debian:
+ integration_test_multi_python_versions_debian_workspace:
<<: *reusable_build_test_all
+ <<: *common_workspace_flags
<<: *coverage_targets_example_multi_python
- name: multi_python_versions integration tests on Debian
+ name: "examples/multi_python_versions: Debian, workspace"
working_directory: examples/multi_python_versions
platform: debian11
- integration_test_multi_python_versions_macos:
+ integration_test_multi_python_versions_macos_workspace:
<<: *reusable_build_test_all
+ <<: *common_workspace_flags
<<: *coverage_targets_example_multi_python
- name: multi_python_versions integration tests on macOS
+ name: "examples/multi_python_versions: MacOS, workspace"
working_directory: examples/multi_python_versions
platform: macos
- integration_test_multi_python_versions_windows:
+ integration_test_multi_python_versions_windows_workspace:
<<: *reusable_build_test_all
+ <<: *common_workspace_flags
# coverage is not supported on Windows
- name: multi_python_versions integration tests on Windows
+ name: "examples/multi_python_versions: Windows, workspace"
working_directory: examples/multi_python_versions
platform: windows
- integration_test_pip_install_ubuntu_min:
+ integration_test_pip_parse_ubuntu_min_workspace:
<<: *minimum_supported_version
+ <<: *common_workspace_flags
<<: *reusable_build_test_all
- name: pip_install integration tests on Ubuntu using minimum supported Bazel version
- working_directory: examples/pip_install
- platform: ubuntu2004
- integration_test_pip_install_ubuntu:
- <<: *reusable_build_test_all
- name: pip_install integration tests on Ubuntu
- working_directory: examples/pip_install
+ name: "examples/pip_parse: Ubuntu, workspace, minimum supporte Bazel version"
+ working_directory: examples/pip_parse
platform: ubuntu2004
- integration_test_pip_install_debian:
- <<: *reusable_build_test_all
- name: pip_install integration tests on Debian
- working_directory: examples/pip_install
- platform: debian11
- integration_test_pip_install_macos:
- <<: *reusable_build_test_all
- name: pip_install integration tests on macOS
- working_directory: examples/pip_install
- platform: macos
- integration_test_pip_install_windows:
- <<: *reusable_build_test_all
- name: pip_install integration tests on Windows
- working_directory: examples/pip_install
- platform: windows
-
- integration_test_pip_parse_ubuntu_min:
+ integration_test_pip_parse_ubuntu_min_bzlmod:
<<: *minimum_supported_version
<<: *reusable_build_test_all
- name: pip_parse integration tests on Ubuntu using minimum supported Bazel version
+ name: "examples/pip_parse: Ubuntu, bzlmod, minimum supporte Bazel version"
working_directory: examples/pip_parse
platform: ubuntu2004
integration_test_pip_parse_ubuntu:
<<: *reusable_build_test_all
- name: pip_parse integration tests on Ubuntu
+ name: "examples/pip_parse: Ubuntu"
working_directory: examples/pip_parse
platform: ubuntu2004
integration_test_pip_parse_debian:
<<: *reusable_build_test_all
- name: pip_parse integration tests on Debian
+ name: "examples/pip_parse: Debian"
working_directory: examples/pip_parse
platform: debian11
integration_test_pip_parse_macos:
<<: *reusable_build_test_all
- name: pip_parse integration tests on macOS
+ name: "examples/pip_parse: MacOS"
working_directory: examples/pip_parse
platform: macos
integration_test_pip_parse_windows:
<<: *reusable_build_test_all
- name: pip_parse integration tests on Windows
+ name: "examples/pip_parse: Windows"
working_directory: examples/pip_parse
platform: windows
- integration_test_pip_parse_vendored_ubuntu_min:
+ integration_test_pip_parse_vendored_ubuntu_min_workspace:
<<: *minimum_supported_version
+ <<: *common_workspace_flags
<<: *reusable_build_test_all
- name: pip_parse_vendored integration tests on Ubuntu using minimum supported Bazel version
+ name: "examples/pip_parse_vendored: Ubuntu, workspace, minimum Bazel"
+ working_directory: examples/pip_parse_vendored
+ platform: ubuntu2004
+ integration_test_pip_parse_vendored_ubuntu_min_bzlmod:
+ <<: *minimum_supported_version
+ <<: *reusable_build_test_all
+ name: "examples/pip_parse_vendored: Ubuntu, bzlmod, minimum Bazel"
working_directory: examples/pip_parse_vendored
platform: ubuntu2004
integration_test_pip_parse_vendored_ubuntu:
<<: *reusable_build_test_all
- name: pip_parse_vendored integration tests on Ubuntu
+ name: "examples/pip_parse_vendored: Ubuntu"
working_directory: examples/pip_parse_vendored
platform: ubuntu2004
integration_test_pip_parse_vendored_debian:
<<: *reusable_build_test_all
- name: pip_parse_vendored integration tests on Debian
+ name: "examples/pip_parse_vendored: Debian"
working_directory: examples/pip_parse_vendored
platform: debian11
integration_test_pip_parse_vendored_macos:
<<: *reusable_build_test_all
- name: pip_parse_vendored integration tests on macOS
+ name: "examples/pip_parse_vendored: MacOS"
working_directory: examples/pip_parse_vendored
platform: macos
# We don't run pip_parse_vendored under Windows as the file checked in is
# generated from a repository rule containing OS-specific rendered paths.
- integration_test_py_proto_library_ubuntu_min:
- <<: *minimum_supported_version
+ # The proto example is workspace-only; bzlmod functionality is covered
+ # by examples/bzlmod/py_proto_library
+ integration_test_py_proto_library_ubuntu_workspace:
<<: *reusable_build_test_all
- name: py_proto_library integration tests on Ubuntu using minimum supported Bazel version
+ <<: *common_workspace_flags
+ name: "examples/py_proto_library: Ubuntu, workspace"
working_directory: examples/py_proto_library
platform: ubuntu2004
- integration_test_py_proto_library_ubuntu:
+ integration_test_py_proto_library_debian_workspace:
<<: *reusable_build_test_all
- name: py_proto_library integration tests on Ubuntu
- working_directory: examples/py_proto_library
- platform: ubuntu2004
- integration_test_py_proto_library_debian:
- <<: *reusable_build_test_all
- name: py_proto_library integration tests on Debian
- working_directory: examples/py_proto_library
- platform: debian11
- integration_test_py_proto_library_macos:
- <<: *reusable_build_test_all
- name: py_proto_library integration tests on macOS
- working_directory: examples/py_proto_library
- platform: macos
- integration_test_py_proto_library_windows:
- <<: *reusable_build_test_all
- name: py_proto_library integration tests on Windows
- working_directory: examples/py_proto_library
- platform: windows
-
- # Check the same using bzlmod as well
- integration_test_py_proto_library_bzlmod_ubuntu_min:
- <<: *minimum_supported_bzlmod_version
- <<: *common_bzlmod_flags
- <<: *reusable_build_test_all
- name: py_proto_library bzlmod integration tests on Ubuntu using minimum supported Bazel version
- working_directory: examples/py_proto_library
- platform: ubuntu2004
- integration_test_py_proto_library_bzlmod_ubuntu:
- <<: *reusable_build_test_all
- <<: *common_bzlmod_flags
- name: py_proto_library bzlmod integration tests on Ubuntu
- working_directory: examples/py_proto_library
- platform: ubuntu2004
- integration_test_py_proto_library_bzlmod_debian:
- <<: *reusable_build_test_all
- <<: *common_bzlmod_flags
- name: py_proto_library bzlmod integration tests on Debian
+ <<: *common_workspace_flags
+ name: "examples/py_proto_library: Debian, workspace"
working_directory: examples/py_proto_library
platform: debian11
- integration_test_py_proto_library_bzlmod_macos:
+ integration_test_py_proto_library_macos_workspace:
<<: *reusable_build_test_all
- <<: *common_bzlmod_flags
- name: py_proto_library bzlmod integration tests on macOS
+ <<: *common_workspace_flags
+ name: "examples/py_proto_library: MacOS, workspace"
working_directory: examples/py_proto_library
platform: macos
- integration_test_py_proto_library_bzlmod_windows:
+ integration_test_py_proto_library_windows_workspace:
<<: *reusable_build_test_all
- <<: *common_bzlmod_flags
- name: py_proto_library bzlmod integration tests on Windows
+ <<: *common_workspace_flags
+ name: "examples/py_proto_library: Windows, workspace"
working_directory: examples/py_proto_library
platform: windows
- integration_test_pip_repository_annotations_ubuntu_min:
- <<: *minimum_supported_version
+ integration_test_pip_repository_annotations_ubuntu_workspace:
<<: *reusable_build_test_all
- name: pip_repository_annotations integration tests on Ubuntu using minimum supported Bazel version
+ <<: *common_workspace_flags
+ name: "examples/pip_repository_annotations: Ubuntu, workspace"
working_directory: examples/pip_repository_annotations
platform: ubuntu2004
- integration_test_pip_repository_annotations_ubuntu:
+ integration_test_pip_repository_annotations_debian_workspace:
<<: *reusable_build_test_all
- name: pip_repository_annotations integration tests on Ubuntu
- working_directory: examples/pip_repository_annotations
- platform: ubuntu2004
- integration_test_pip_repository_annotations_debian:
- <<: *reusable_build_test_all
- name: pip_repository_annotations integration tests on Debian
+ <<: *common_workspace_flags
+ name: "examples/pip_repository_annotations: Debian, workspace"
working_directory: examples/pip_repository_annotations
platform: debian11
- integration_test_pip_repository_annotations_macos:
+ integration_test_pip_repository_annotations_macos_workspace:
<<: *reusable_build_test_all
- name: pip_repository_annotations integration tests on macOS
+ <<: *common_workspace_flags
+ name: "examples/pip_repository_annotations: macOS, workspace"
working_directory: examples/pip_repository_annotations
platform: macos
- integration_test_pip_repository_annotations_windows:
+ integration_test_pip_repository_annotations_windows_workspace:
<<: *reusable_build_test_all
- name: pip_repository_annotations integration tests on Windows
+ <<: *common_workspace_flags
+ name: "examples/pip_repository_annotations: Windows, workspace"
working_directory: examples/pip_repository_annotations
platform: windows
- integration_test_compile_pip_requirements_ubuntu_min:
- <<: *minimum_supported_version
- <<: *reusable_build_test_all
- name: compile_pip_requirements integration tests on Ubuntu using minimum supported Bazel version
- working_directory: tests/compile_pip_requirements
+ integration_test_bazelinbazel_ubuntu:
+ <<: *common_bazelinbazel_config
+ name: "tests/integration bazel-in-bazel: Ubuntu"
platform: ubuntu2004
+ integration_test_bazelinbazel_debian:
+ <<: *common_bazelinbazel_config
+ name: "tests/integration bazel-in-bazel: Debian"
+ platform: debian11
+
integration_test_compile_pip_requirements_ubuntu:
<<: *reusable_build_test_all
- name: compile_pip_requirements integration tests on Ubuntu
- working_directory: tests/compile_pip_requirements
+ name: "compile_pip_requirements: Ubuntu"
+ working_directory: tests/integration/compile_pip_requirements
platform: ubuntu2004
shell_commands:
# Make a change to the locked requirements and then assert that //:requirements.update does the
@@ -454,8 +462,8 @@ tasks:
- "git diff --exit-code"
integration_test_compile_pip_requirements_debian:
<<: *reusable_build_test_all
- name: compile_pip_requirements integration tests on Debian
- working_directory: tests/compile_pip_requirements
+ name: "compile_pip_requirements: Debian"
+ working_directory: tests/integration/compile_pip_requirements
platform: debian11
shell_commands:
# Make a change to the locked requirements and then assert that //:requirements.update does the
@@ -472,8 +480,8 @@ tasks:
- "git diff --exit-code"
integration_test_compile_pip_requirements_macos:
<<: *reusable_build_test_all
- name: compile_pip_requirements integration tests on macOS
- working_directory: tests/compile_pip_requirements
+ name: "compile_pip_requirements: MacOS"
+ working_directory: tests/integration/compile_pip_requirements
platform: macos
shell_commands:
# Make a change to the locked requirements and then assert that //:requirements.update does the
@@ -490,8 +498,8 @@ tasks:
- "git diff --exit-code"
integration_test_compile_pip_requirements_windows:
<<: *reusable_build_test_all
- name: compile_pip_requirements integration tests on Windows
- working_directory: tests/compile_pip_requirements
+ name: "compile_pip_requirements: Windows"
+ working_directory: tests/integration/compile_pip_requirements
platform: windows
shell_commands:
# Make a change to the locked requirements and then assert that //:requirements.update does the
@@ -507,94 +515,74 @@ tasks:
- "bazel run //:os_specific_requirements.update"
- "git diff --exit-code"
- integration_test_pip_repository_entry_points_ubuntu_min:
- <<: *minimum_supported_version
- <<: *reusable_build_test_all
- name: pip_repository_entry_points integration tests on Ubuntu using minimum supported Bazel version
- working_directory: tests/pip_repository_entry_points
- platform: ubuntu2004
- integration_test_pip_repository_entry_points_ubuntu:
+ integration_test_pip_repository_entry_points_macos_workspace:
<<: *reusable_build_test_all
- name: pip_repository_entry_points integration tests on Ubuntu
- working_directory: tests/pip_repository_entry_points
- platform: ubuntu2004
- integration_test_pip_repository_entry_points_debian:
- <<: *reusable_build_test_all
- name: pip_repository_entry_points integration tests on Debian
- working_directory: tests/pip_repository_entry_points
- platform: debian11
- integration_test_pip_repository_entry_points_macos:
- <<: *reusable_build_test_all
- name: pip_repository_entry_points integration tests on macOS
- working_directory: tests/pip_repository_entry_points
+ <<: *common_workspace_flags
+ name: "pip_repository_entry_points: macOS, workspace"
+ working_directory: tests/integration/pip_repository_entry_points
platform: macos
- integration_test_pip_repository_entry_points_windows:
+ integration_test_pip_repository_entry_points_windows_workspace:
<<: *reusable_build_test_all
- name: pip_repository_entry_points integration tests on Windows
- working_directory: tests/pip_repository_entry_points
+ <<: *common_workspace_flags
+ name: "pip_repository_entry_points: Windows, workspace"
+ working_directory: tests/integration/pip_repository_entry_points
platform: windows
- integration_test_ignore_root_user_error_ubuntu_min:
- <<: *minimum_supported_version
+ integration_test_ignore_root_user_error_macos_workspace:
<<: *reusable_build_test_all
- name: ignore_root_user_error integration tests on Ubuntu using minimum supported Bazel version
- working_directory: tests/ignore_root_user_error
- platform: ubuntu2004
- integration_test_ignore_root_user_error_ubuntu:
- <<: *reusable_build_test_all
- name: ignore_root_user_error integration tests on Ubuntu
- working_directory: tests/ignore_root_user_error
- platform: ubuntu2004
- integration_test_ignore_root_user_error_debian:
- <<: *reusable_build_test_all
- name: ignore_root_user_error integration tests on Debian
- working_directory: tests/ignore_root_user_error
- platform: debian11
- integration_test_ignore_root_user_error_macos:
- <<: *reusable_build_test_all
- name: ignore_root_user_error integration tests on macOS
- working_directory: tests/ignore_root_user_error
+ <<: *common_workspace_flags
+ name: "ignore_root_user_error: macOS, workspace"
+ working_directory: tests/integration/ignore_root_user_error
platform: macos
- integration_test_ignore_root_user_error_windows:
+ integration_test_ignore_root_user_error_windows_workspace:
<<: *reusable_build_test_all
- name: ignore_root_user_error integration tests on Windows
- working_directory: tests/ignore_root_user_error
+ <<: *common_workspace_flags
+ name: "ignore_root_user_error: Windows, workspace"
+ working_directory: tests/integration/ignore_root_user_error
platform: windows
- integration_compile_pip_requirements_test_from_external_repo_ubuntu_min:
+ integration_compile_pip_requirements_test_from_external_repo_ubuntu_min_workspace:
<<: *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
+ <<: *common_workspace_flags
+ name: "compile_pip_requirements_test_from_external_repo: Ubuntu, workspace, minimum Bazel"
+ working_directory: tests/integration/compile_pip_requirements_test_from_external_repo
platform: ubuntu2004
shell_commands:
- # Assert that @external_repository//:requirements_test does the right thing.
- - "bazel test @external_repository//..."
+ # Assert that @compile_pip_requirements//:requirements_test does the right thing.
+ - "bazel test @compile_pip_requirements//..."
+ integration_compile_pip_requirements_test_from_external_repo_ubuntu_min_bzlmod:
+ <<: *minimum_supported_version
+ name: "compile_pip_requirements_test_from_external_repo: Ubuntu, bzlmod, minimum Bazel"
+ working_directory: tests/integration/compile_pip_requirements_test_from_external_repo
+ platform: ubuntu2004
+ shell_commands:
+ # Assert that @compile_pip_requirements//:requirements_test does the right thing.
+ - "bazel test @compile_pip_requirements//..."
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
+ name: "compile_pip_requirements_test_from_external_repo: Ubuntu"
+ working_directory: tests/integration/compile_pip_requirements_test_from_external_repo
platform: ubuntu2004
shell_commands:
- # Assert that @external_repository//:requirements_test does the right thing.
- - "bazel test @external_repository//..."
+ # Assert that @compile_pip_requirements//:requirements_test does the right thing.
+ - "bazel test @compile_pip_requirements//..."
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
+ name: "compile_pip_requirements_test_from_external_repo: Debian"
+ working_directory: tests/integration/compile_pip_requirements_test_from_external_repo
platform: debian11
shell_commands:
- # Assert that @external_repository//:requirements_test does the right thing.
- - "bazel test @external_repository//..."
+ # Assert that @compile_pip_requirements//:requirements_test does the right thing.
+ - "bazel test @compile_pip_requirements//..."
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
+ name: "compile_pip_requirements_test_from_external_repo: macOS"
+ working_directory: tests/integration/compile_pip_requirements_test_from_external_repo
platform: macos
shell_commands:
- # Assert that @external_repository//:requirements_test does the right thing.
- - "bazel test @external_repository//..."
+ # Assert that @compile_pip_requirements//:requirements_test does the right thing.
+ - "bazel test @compile_pip_requirements//..."
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
+ name: "compile_pip_requirements_test_from_external_repo: Windows"
+ working_directory: tests/integration/compile_pip_requirements_test_from_external_repo
platform: windows
shell_commands:
- # Assert that @external_repository//:requirements_test does the right thing.
- - "bazel test @external_repository//..."
-
+ # Assert that @compile_pip_requirements//:requirements_test does the right thing.
+ - "bazel test @compile_pip_requirements//..."
diff --git a/.bazelignore b/.bazelignore
index 135f709..9bcb523 100644
--- a/.bazelignore
+++ b/.bazelignore
@@ -6,6 +6,23 @@ bazel-rules_python
bazel-bin
bazel-out
bazel-testlogs
+# Prevent the convenience symlinks within the examples from being
+# treated as directories with valid BUILD files for the main repo.
+# Any directory with a WORKSPACE in it should be added here, with
+# an entry like `bazel-{workspacename}`
+examples/bzlmod/bazel-bin
examples/bzlmod/bazel-bzlmod
+examples/bzlmod/bazel-out
+examples/bzlmod/bazel-testlogs
+examples/bzlmod/other_module/bazel-bin
+examples/bzlmod/other_module/bazel-other_module
+examples/bzlmod/other_module/bazel-out
+examples/bzlmod/other_module/bazel-testlogs
examples/bzlmod_build_file_generation/bazel-bzlmod_build_file_generation
+examples/multi_python_versions/bazel-multi_python_versions
+examples/pip_parse/bazel-pip_parse
+examples/pip_parse_vendored/bazel-pip_parse_vendored
examples/py_proto_library/bazel-py_proto_library
+tests/integration/compile_pip_requirements/bazel-compile_pip_requirements
+tests/integration/ignore_root_user_error/bazel-ignore_root_user_error
+tests/integration/pip_repository_entry_points/bazel-pip_repository_entry_points
diff --git a/.bazelrc b/.bazelrc
index 87fa6d5..250377a 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -2,9 +2,10 @@
# Trick bazel into treating BUILD files under examples/* as being regular files
# 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/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/whl_mods,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/libs/my_lib,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/whl_mods,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
+# To update these lines, execute
+# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
+build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/dupe_requirements,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/ignore_root_user_error,tests/integration/pip_repository_entry_points,tests/integration/py_cc_toolchain_registered
+query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/dupe_requirements,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/ignore_root_user_error,tests/integration/pip_repository_entry_points,tests/integration/py_cc_toolchain_registered
test --test_output=errors
@@ -19,3 +20,13 @@ build --incompatible_default_to_explicit_init_py
# Windows makes use of runfiles for some rules
build --enable_runfiles
startup --windows_enable_symlinks
+
+# Make Bazel 6 use bzlmod by default
+common --enable_bzlmod
+
+# Additional config to use for readthedocs builds.
+# See .readthedocs.yml for additional flags that can only be determined from
+# the runtime environment.
+build:rtd --stamp
+# Some bzl files contain repos only available under bzlmod
+build:rtd --enable_bzlmod
diff --git a/.bazelversion b/.bazelversion
index 09b254e..66ce77b 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-6.0.0
+7.0.0
diff --git a/.bcr/config.yml b/.bcr/config.yml
index 7bdd70f..7672aa5 100644
--- a/.bcr/config.yml
+++ b/.bcr/config.yml
@@ -14,5 +14,5 @@
fixedReleaser:
login: f0rmiga
- email: thulio@aspect.dev
+ email: 3149049+f0rmiga@users.noreply.github.com
moduleRoots: [".", "gazelle"]
diff --git a/.gitattributes b/.gitattributes
index 64d09ff..e4e5d4b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1 @@
-docs/*.md linguist-generated=true
tools/publish/*.txt linguist-generated=true
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 0d305b8..c347266 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,8 +1,10 @@
PR Instructions/requirements
* Title uses `type: description` format. See CONTRIBUTING.md for types.
-* Common types are: build, docs, feat, fix, refactor, revert, test
+ * Common types are: build, docs, feat, fix, refactor, revert, test
+ * Update `CHANGELOG.md` as applicable
* Breaking changes include "!" after the type and a "BREAKING CHANGES:"
section at the bottom.
+ See CONTRIBUTING.md for our breaking changes process.
* Body text describes:
* Why this change is being made, briefly.
* Before and after behavior, as applicable
diff --git a/.github/workflows/create_archive_and_notes.sh b/.github/workflows/create_archive_and_notes.sh
index f7a291a..ffeecd5 100755
--- a/.github/workflows/create_archive_and_notes.sh
+++ b/.github/workflows/create_archive_and_notes.sh
@@ -37,7 +37,8 @@ bazel_dep(name = "rules_python", version = "${TAG}")
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
- name = "pip",
+ hub_name = "pip",
+ python_version = "3.11",
requirements_lock = "//:requirements_lock.txt",
)
diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml
new file mode 100644
index 0000000..b0d0cdf
--- /dev/null
+++ b/.github/workflows/mypy.yaml
@@ -0,0 +1,32 @@
+name: mypy
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ types:
+ - opened
+ - synchronize
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ ci:
+ runs-on: ubuntu-20.04
+ steps:
+ # Checkout the code
+ - uses: actions/checkout@v2
+ - uses: jpetrucciani/mypy-check@master
+ with:
+ requirements: 1.6.0
+ python_version: 3.8
+ path: 'python/runfiles'
+ - uses: jpetrucciani/mypy-check@master
+ with:
+ requirements: 1.6.0
+ python_version: 3.8
+ path: 'tests/runfiles'
+
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e501053..060cb9c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -20,7 +20,7 @@ repos:
rev: 6.1.0
hooks:
- id: buildifier
- args: &args
+ args: &args
# Keep this argument in sync with .bazelci/presubmit.yaml
- --warnings=all
- id: buildifier-lint
@@ -30,7 +30,7 @@ repos:
hooks:
- id: isort
name: isort (python)
- args:
+ args:
- --profile
- black
- repo: https://github.com/psf/black
@@ -42,6 +42,6 @@ repos:
- id: update-deleted-packages
name: Update deleted packages
language: script
- entry: ./tools/bazel_integration_test/update_deleted_packages.sh
- files: ^((examples|tests)/*/(MODULE.bazel|WORKSPACE|WORKSPACE.bzlmod|BUILD.bazel)|.bazelrc|tools/bazel_integration_test/update_deleted_packages.sh)$
+ entry: bazel run @rules_bazel_integration_test//tools:update_deleted_packages
+ files: ^((examples|tests)/.*/(MODULE.bazel|WORKSPACE|WORKSPACE.bzlmod|BUILD.bazel)|.bazelrc)$
pass_filenames: false
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 0000000..f68ccc8
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,14 @@
+
+version: 2
+
+build:
+ os: "ubuntu-22.04"
+ tools:
+ nodejs: "19"
+ commands:
+ - env
+ - npm install -g @bazel/bazelisk
+ - bazel version
+ # Put the actual build behind a shell script because its easier to modify than
+ # the yaml config.
+ - docs/sphinx/readthedocs_build.sh
diff --git a/BUILD.bazel b/BUILD.bazel
index 35a3df8..cd4cbc5 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load(":version.bzl", "BAZEL_VERSION")
package(default_visibility = ["//visibility:public"])
@@ -23,6 +24,11 @@ exports_files([
"version.bzl",
])
+exports_files(
+ glob(["*.md"]),
+ visibility = ["//docs:__subpackages__"],
+)
+
filegroup(
name = "distribution",
srcs = [
@@ -38,12 +44,16 @@ filegroup(
"@rules_python_gazelle_plugin//:distribution",
],
visibility = [
- "//examples:__pkg__",
- "//python/tests/toolchains:__pkg__",
- "//tests:__pkg__",
+ "//:__subpackages__",
],
)
+bzl_library(
+ name = "version_bzl",
+ srcs = ["version.bzl"],
+ visibility = ["//:__subpackages__"],
+)
+
# Reexport of all bzl files used to allow downstream rules to generate docs
# without shipping with a dependency on Skylib
filegroup(
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..af61b44
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,336 @@
+# rules_python Changelog
+
+This is a human-friendly changelog in a keepachangelog.com style format.
+Because this changelog is for end-user consumption of meaningful changes,only
+a summary of a release's changes is described. This means every commit is not
+necessarily mentioned, and internal refactors or code cleanups are omitted
+unless they're particularly notable.
+
+A brief description of the categories of changes:
+
+* `Changed`: Some behavior changed. If the change is expected to break a
+ public API or supported behavior, it will be marked as **BREAKING**. Note that
+ beta APIs will not have breaking API changes called out.
+* `Fixed`: A bug, or otherwise incorrect behavior, was fixed.
+* `Added`: A new feature, API, or behavior was added in a backwards compatible
+ manner.
+* Particular sub-systems are identified using parentheses, e.g. `(bzlmod)` or
+ `(docs)`.
+
+## Unreleased
+
+[0.XX.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.XX.0
+
+### Changed
+
+### Fixed
+
+### Added
+
+## [0.28.0] - 2024-01-07
+
+[0.28.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.28.0
+
+### Changed
+
+* **BREAKING** (pip_install) the deprecated `pip_install` macro and related
+ items have been removed.
+
+* **BREAKING** Support for Bazel 5 has been officially dropped. This release
+ was only partially tested with Bazel 5 and may or may not work with Bazel 5.
+ Subequent versions will no longer be tested under Bazel 5.
+
+* (runfiles) `rules_python.python.runfiles` now directly implements type hints
+ and drops support for python2 as a result.
+
+* (toolchains) `py_runtime`, `py_runtime_pair`, and `PyRuntimeInfo` now use the
+ rules_python Starlark implementation, not the one built into Bazel. NOTE: This
+ only applies to Bazel 6+; Bazel 5 still uses the builtin implementation.
+
+* (pip_parse) The parameter `experimental_requirement_cycles` may be provided a
+ map of names to lists of requirements which form a dependency
+ cycle. `pip_parse` will break the cycle for you transparently. This behavior
+ is also available under bzlmod as
+ `pip.parse(experimental_requirement_cycles={})`.
+
+* (toolchains) `py_runtime` can now take an executable target. Note: runfiles
+ from the target are not supported yet.
+ ([#1612](https://github.com/bazelbuild/rules_python/issues/1612))
+
+### Fixed
+
+* (gazelle) The gazelle plugin helper was not working with Python toolchains 3.11
+ and above due to a bug in the helper components not being on PYTHONPATH.
+
+* (pip_parse) The repositories created by `whl_library` can now parse the `whl`
+ METADATA and generate dependency closures irrespective of the host platform
+ the generation is executed on. This can be turned on by supplying
+ `experimental_target_platforms = ["all"]` to the `pip_parse` or the `bzlmod`
+ equivalent. This may help in cases where fetching wheels for a different
+ platform using `download_only = True` feature.
+* (bzlmod pip.parse) The `pip.parse(python_interpreter)` arg now works for
+ specifying a local system interpreter.
+* (bzlmod pip.parse) Requirements files with duplicate entries for the same
+ package (e.g. one for the package, one for an extra) now work.
+* (bzlmod python.toolchain) Submodules can now (re)register the Python version
+ that rules_python has set as the default.
+ ([#1638](https://github.com/bazelbuild/rules_python/issues/1638))
+* (whl_library) Actually use the provided patches to patch the whl_library.
+ On Windows the patching may result in files with CRLF line endings, as a result
+ the RECORD file consistency requirement is lifted and now a warning is emitted
+ instead with a location to the patch that could be used to silence the warning.
+ Copy the patch to your workspace and add it to the list if patches for the wheel
+ file if you decide to do so.
+* (coverage): coverage reports are now created when the version-aware
+ rules are used.
+ ([#1600](https://github.com/bazelbuild/rules_python/issues/1600))
+* (toolchains) Workspace builds register the py cc toolchain (bzlmod already
+ was). This makes e.g. `//python/cc:current_py_cc_headers` Just Work.
+ ([#1669](https://github.com/bazelbuild/rules_python/issues/1669))
+
+### Added
+
+* (docs) bzlmod extensions are now documented on rules-python.readthedocs.io
+* (docs) Support and backwards compatibility policies have been documented.
+ See https://rules-python.readthedocs.io/en/latest/support.html
+* (gazelle) `file` generation mode can now also add `__init__.py` to the srcs
+ attribute for every target in the package. This is enabled through a separate
+ directive `python_generation_mode_per_file_include_init`.
+
+
+## [0.27.0] - 2023-11-16
+
+[0.27.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.27.0
+
+### Changed
+
+* Make `//python/pip_install:pip_repository_bzl` `bzl_library` target internal
+ as all of the publicly available symbols (etc. `package_annotation`) are
+ re-exported via `//python:pip_bzl` `bzl_library`.
+
+* (gazelle) Gazelle Python extension no longer has runtime dependencies. Using
+ `GAZELLE_PYTHON_RUNTIME_DEPS` from `@rules_python_gazelle_plugin//:def.bzl` is
+ no longer necessary.
+
+* (pip_parse) The installation of `pip_parse` repository rule toolchain
+ dependencies is now done as part of `py_repositories` call.
+
+* (pip_parse) The generated `requirements.bzl` file now has an additional symbol
+ `all_whl_requirements_by_package` which provides a map from the normalized
+ PyPI package name to the target that provides the built wheel file. Use
+ `pip_utils.normalize_name` function from `@rules_python//python:pip.bzl` to
+ convert a PyPI package name to a key in the `all_whl_requirements_by_package`
+ map.
+
+* (pip_parse) The flag `incompatible_generate_aliases` has been flipped to
+ `True` by default on `non-bzlmod` setups allowing users to use the same label
+ strings during the transition period. For example, instead of
+ `@pypi_foo//:pkg`, you can now use `@pypi//foo` or `@pypi//foo:pkg`. Other
+ labels that are present in the `foo` package are `dist_info`, `whl` and
+ `data`. Note, that the `@pypi_foo//:pkg` labels are still present for
+ backwards compatibility.
+
+* (gazelle) The flag `use_pip_repository_aliases` is now set to `True` by
+ default, which will cause `gazelle` to change third-party dependency labels
+ from `@pip_foo//:pkg` to `@pip//foo` by default.
+
+* The `compile_pip_requirements` now defaults to `pyproject.toml` if the `src`
+ or `requirements_in` attributes are unspecified, matching the upstream
+ `pip-compile` behaviour more closely.
+
+* (gazelle) Use relative paths if possible for dependencies added through
+ the use of the `resolve` directive.
+
+* (gazelle) When using `python_generation_mode file`, one `py_test` target is
+ made per test file even if a target named `__test__` or a file named
+ `__test__.py` exists in the same package. Previously in these cases there
+ would only be one test target made.
+
+Breaking changes:
+
+* (pip) `pip_install` repository rule in this release has been disabled and
+ will fail by default. The API symbol is going to be removed in the next
+ version, please migrate to `pip_parse` as a replacement. The `pip_parse`
+ rule no longer supports `requirements` attribute, please use
+ `requirements_lock` instead.
+
+* (py_wheel) switch `incompatible_normalize_name` and
+ `incompatible_normalize_version` to `True` by default to enforce `PEP440`
+ for wheel names built by `rules_python`.
+
+* (tools/wheelmaker.py) drop support for Python 2 as only Python 3 is tested.
+
+### Fixed
+
+* Skip aliases for unloaded toolchains. Some Python versions that don't have full
+ platform support, and referencing their undefined repositories can break operations
+ like `bazel query rdeps(...)`.
+
+* Python code generated from `proto_library` with `strip_import_prefix` can be imported now.
+
+* (py_wheel) Produce deterministic wheel files and make `RECORD` file entries
+ follow the order of files written to the `.whl` archive.
+
+* (gazelle) Generate a single `py_test` target when `gazelle:python_generation_mode project`
+ is used.
+
+* (gazelle) Move waiting for the Python interpreter process to exit to the shutdown hook
+ to make the usage of the `exec.Command` more idiomatic.
+
+* (toolchains) Keep tcl subdirectory in Windows build of hermetic interpreter.
+
+* (bzlmod) sub-modules now don't have the `//conditions:default` clause in the
+ hub repos created by `pip.parse`. This should fix confusing error messages
+ in case there is a misconfiguration of toolchains or a bug in `rules_python`.
+
+### Added
+
+* (bzlmod) Added `.whl` patching support via `patches` and `patch_strip`
+ arguments to the new `pip.override` tag class.
+
+* (pip) Support for using [PEP621](https://peps.python.org/pep-0621/) compliant
+ `pyproject.toml` for creating a resolved `requirements.txt` file.
+
+* (utils) Added a `pip_utils` struct with a `normalize_name` function to allow users
+ to find out how `rules_python` would normalize a PyPI distribution name.
+
+[0.27.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.27.0
+
+## [0.26.0] - 2023-10-06
+
+### Changed
+
+* Python version patch level bumps:
+ * 3.8.15 -> 3.8.18
+ * 3.9.17 -> 3.9.18
+ * 3.10.12 -> 3.10.13
+ * 3.11.4 -> 3.11.6
+
+* (deps) Upgrade rules_go 0.39.1 -> 0.41.0; this is so gazelle integration works with upcoming Bazel versions
+
+* (multi-version) The `distribs` attribute is no longer propagated. This
+ attribute has been long deprecated by Bazel and shouldn't be used.
+
+* Calling `//python:repositories.bzl#py_repositories()` is required. It has
+ always been documented as necessary, but it was possible to omit it in certain
+ cases. An error about `@rules_python_internal` means the `py_repositories()`
+ call is missing in `WORKSPACE`.
+
+* (bzlmod) The `pip.parse` extension will generate os/arch specific lock
+ file entries on `bazel>=6.4`.
+
+
+### Added
+
+* (bzlmod, entry_point) Added
+ [`py_console_script_binary`](./docs/py_console_script_binary.md), which
+ allows adding custom dependencies to a package's entry points and customizing
+ the `py_binary` rule used to build it.
+
+* New Python versions available: `3.8.17`, `3.11.5` using
+ https://github.com/indygreg/python-build-standalone/releases/tag/20230826.
+
+* (gazelle) New `# gazelle:python_generation_mode file` directive to support
+ generating one `py_library` per file.
+
+* (python_repository) Support `netrc` and `auth_patterns` attributes to enable
+ authentication against private HTTP hosts serving Python toolchain binaries.
+
+* `//python:packaging_bzl` added, a `bzl_library` for the Starlark
+ files `//python:packaging.bzl` requires.
+* (py_wheel) Added the `incompatible_normalize_name` feature flag to
+ normalize the package distribution name according to latest Python
+ packaging standards. Defaults to `False` for the time being.
+* (py_wheel) Added the `incompatible_normalize_version` feature flag
+ to normalize the package version according to PEP440 standard. This
+ also adds support for local version specifiers (versions with a `+`
+ in them), in accordance with PEP440. Defaults to `False` for the
+ time being.
+
+* New Python versions available: `3.8.18`, `3.9.18`, `3.10.13`, `3.11.6`, `3.12.0` using
+ https://github.com/indygreg/python-build-standalone/releases/tag/20231002.
+ `3.12.0` support is considered beta and may have issues.
+
+### Removed
+
+* (bzlmod) The `entry_point` macro is no longer supported and has been removed
+ in favour of the `py_console_script_binary` macro for `bzlmod` users.
+
+* (bzlmod) The `pip.parse` no longer generates `{hub_name}_{py_version}` hub repos
+ as the `entry_point` macro has been superseded by `py_console_script_binary`.
+
+* (bzlmod) The `pip.parse` no longer generates `{hub_name}_{distribution}` hub repos.
+
+### Fixed
+
+* (whl_library) No longer restarts repository rule when fetching external
+ dependencies improving initial build times involving external dependency
+ fetching.
+
+* (gazelle) Improve runfiles lookup hermeticity.
+
+[0.26.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.26.0
+
+## [0.25.0] - 2023-08-22
+
+### Changed
+
+* Python version patch level bumps:
+ * 3.9.16 -> 3.9.17
+ * 3.10.9 -> 3.10.12
+ * 3.11.1 -> 3.11.4
+* (bzlmod) `pip.parse` can no longer automatically use the default
+ Python version; this was an unreliable and unsafe behavior. The
+ `python_version` arg must always be explicitly specified.
+
+### Fixed
+
+* (docs) Update docs to use correct bzlmod APIs and clarify how and when to use
+ various APIs.
+* (multi-version) The `main` arg is now correctly computed and usually optional.
+* (bzlmod) `pip.parse` no longer requires a call for whatever the configured
+ default Python version is.
+
+### Added
+
+* Created a changelog.
+* (gazelle) Stop generating unnecessary imports.
+* (toolchains) s390x supported for Python 3.9.17, 3.10.12, and 3.11.4.
+
+[0.25.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.25.0
+
+## [0.24.0] - 2023-07-11
+
+### Changed
+
+* **BREAKING** (gazelle) Gazelle 0.30.0 or higher is required
+* (bzlmod) `@python_aliases` renamed to `@python_versions
+* (bzlmod) `pip.parse` arg `name` renamed to `hub_name`
+* (bzlmod) `pip.parse` arg `incompatible_generate_aliases` removed and always
+ true.
+
+### Fixed
+
+* (bzlmod) Fixing Windows Python Interpreter symlink issues
+* (py_wheel) Allow twine tags and args
+* (toolchain, bzlmod) Restrict coverage tool visibility under bzlmod
+* (pip) Ignore temporary pyc.NNN files in wheels
+* (pip) Add format() calls to glob_exclude templates
+* plugin_output in py_proto_library rule
+
+### Added
+
+* Using Gazelle's lifecycle manager to manage external processes
+* (bzlmod) `pip.parse` can be called multiple times with different Python
+ versions
+* (bzlmod) Allow bzlmod `pip.parse` to reference the default python toolchain and interpreter
+* (bzlmod) Implementing wheel annotations via `whl_mods`
+* (gazelle) support multiple requirements files in manifest generation
+* (py_wheel) Support for specifying `Description-Content-Type` and `Summary` in METADATA
+* (py_wheel) Support for specifying `Project-URL`
+* (compile_pip_requirements) Added `generate_hashes` arg (default True) to
+ control generating hashes
+* (pip) Create all_data_requirements alias
+* Expose Python C headers through the toolchain.
+
+[0.24.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.24.0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 54ecfb0..10d1149 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,10 +65,6 @@ and setup. Subsequent runs will be faster, but there are many tests, and some of
them are slow. If you're working on a particular area of code, you can run just
the tests in those directories instead, which can speed up your edit-run cycle.
-Note that there are tests to verify generated documentation is correct -- if
-you're modifying the signature of a public function, these tests will likely
-fail and you'll need to [regenerate the api docs](#documentation).
-
## Formatting
Starlark files should be formatted by
@@ -128,7 +124,9 @@ BREAKING CHANGE: <summary>
```
Where `(scope)` is optional, and `!` is only required if there is a breaking change.
-If a breaking change is introduced, then `BREAKING CHANGE:` is required.
+If a breaking change is introduced, then `BREAKING CHANGE:` is required; see
+the [Breaking Changes](#breaking-changes) section for how to introduce breaking
+changes.
Common `type`s:
@@ -146,18 +144,11 @@ For the full details of types, see
## Generated files
Some checked-in files are generated and need to be updated when a new PR is
-merged.
-
-### Documentation
+merged:
-To regenerate the content under the `docs/` directory, run this command:
-
-```shell
-bazel run //docs:update
-```
-
-This needs to be done whenever the docstrings in the corresponding .bzl files
-are changed; a test failure will remind you to run this command when needed.
+* **requirements lock files**: These are usually generated by a
+ `compile_pip_requirements` update target, which is usually in the same directory.
+ e.g. `bazel run //docs/sphinx:requirements.update`
## Core rules
@@ -184,6 +175,78 @@ Issues should be triaged as follows:
functionality, should also be filed in this repository but without the
`core-rules` label.
+## Breaking Changes
+
+Breaking changes are generally permitted, but we follow a 3-step process for
+introducing them. The intent behind this process is to balance the difficulty of
+version upgrades for users, maintaining multiple code paths, and being able to
+introduce modern functionality.
+
+The general process is:
+
+1. In version `N`, introduce the new behavior, but it must be disabled by
+ default. Users can opt into the new functionality when they upgrade to
+ version `N`, which lets them try it and verify functionality.
+2. In version `N+1`, the new behavior can be enabled by default. Users can
+ opt out if necessary, but doing so causes a warning to be issued.
+3. In version `N+2`, the new behavior is always enabled and cannot be opted out
+ of. The API for the control mechanism can be removed in this release.
+
+Note that the `+1` and `+2` releases are just examples; the steps are not
+required to happen in immedially subsequent releases.
+
+
+### How to control breaking changes
+
+The details of the control mechanism will depend on the situation. Below is
+a summary of some different options.
+
+* Environment variables are best for repository rule behavior. Environment
+ variables can be propagated to rules and macros using the generated
+ `@rules_python_internal//:config.bzl` file.
+* Attributes are applicable to macros and regular rules, especially when the
+ behavior is likely to vary on a per-target basis.
+* [User defined build settings](https://bazel.build/extending/config#user-defined-build-settings)
+ (aka custom build flags) are applicable for rules when the behavior change
+ generally wouldn't vary on a per-target basis. They also have the benefit that
+ an entire code base can have them easily enabled by a bazel command line flag.
+* Allowlists allow a project to centrally control if something is
+ enabled/disabled. Under the hood, they are basically a specialized custom
+ build flag.
+
+Note that attributes and flags can seamlessly interoperate by having the default
+controlled by a flag, and an attribute can override the flag setting. This
+allows a project to enable the new behavior by default while they work to fix
+problematic cases to prepare for the next upgrade.
+
+### What is considered a breaking change?
+
+Precisely defining what constitutes a breaking change is hard because it's
+easy for _someone, somewhere_ to depend on _some_ observable behavior, despite
+our best efforts to thoroughly document what is or isn't supported and hiding
+any internal details.
+
+In general, something is considered a breaking change when it changes the
+direct behavior of a supported public API. Simply being able to observe a
+behavior change doesn't necessarily mean it's a breaking change.
+
+Long standing undocumented behavior is a large grey area and really depends on
+how load-bearing it has become and what sort of reasonable expectation of
+behavior there is.
+
+Here's some examples of what would or wouldn't be considered a breaking change.
+
+Breaking changes:
+ * Renaming an function argument for public functions.
+ * Enforcing stricter validation than was previously required when there's a
+ sensible reason users would run afoul of it.
+ * Changing the name of a public rule.
+
+Not breaking changes:
+ * Upgrading dependencies
+ * Changing internal details, such as renaming an internal file.
+ * Changing a rule to a macro.
+
## FAQ
### Installation errors when during `git commit`
diff --git a/DEVELOPING.md b/DEVELOPING.md
index 2972d96..3c9e89d 100644
--- a/DEVELOPING.md
+++ b/DEVELOPING.md
@@ -1,5 +1,16 @@
# For Developers
+## Updating internal dependencies
+
+1. Modify the `./python/pip_install/tools/requirements.txt` file and run:
+ ```
+ bazel run //tools/private/update_deps:update_pip_deps
+ ```
+1. Bump the coverage dependencies using the script using:
+ ```
+ bazel run //tools/private/update_deps:update_coverage_deps <VERSION>
+ ```
+
## Releasing
Start from a clean checkout at `main`.
diff --git a/METADATA b/METADATA
index 0b420e0..9e28b71 100644
--- a/METADATA
+++ b/METADATA
@@ -1,15 +1,19 @@
-name: "bazelbuild-rules_python"
-description:
- "A repository of Starlark implementation of Python rules in Bazel"
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update bazelbuild-rules_python
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+name: "bazelbuild-rules_python"
+description: "A repository of Starlark implementation of Python rules in Bazel"
third_party {
- url {
- type: GIT
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2024
+ month: 1
+ day: 16
+ }
+ identifier {
+ type: "Git"
value: "https://github.com/bazelbuild/rules_python"
+ version: "0.28.0"
}
- version: "4082693e23ec9615f3e9b2ed9fae542e2b3bed12"
- last_upgrade_date { year: 2023 month: 7 day: 24 }
- license_type: NOTICE
}
-
-
diff --git a/MODULE.bazel b/MODULE.bazel
index b7a0411..e89b8ef 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -4,17 +4,20 @@ module(
compatibility_level = 1,
)
-bazel_dep(name = "platforms", version = "0.0.4")
+bazel_dep(name = "bazel_features", version = "1.1.1")
bazel_dep(name = "bazel_skylib", version = "1.3.0")
+bazel_dep(name = "platforms", version = "0.0.4")
# Those are loaded only when using py_proto_library
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/private:internal_deps.bzl", "internal_deps")
+internal_deps = use_extension("@rules_python//python/private/bzlmod:internal_deps.bzl", "internal_deps")
internal_deps.install()
use_repo(
internal_deps,
+ "rules_python_internal",
+ # START: maintained by 'bazel run //tools/private:update_pip_deps'
"pypi__build",
"pypi__click",
"pypi__colorama",
@@ -25,10 +28,12 @@ use_repo(
"pypi__pep517",
"pypi__pip",
"pypi__pip_tools",
+ "pypi__pyproject_hooks",
"pypi__setuptools",
"pypi__tomli",
"pypi__wheel",
"pypi__zipp",
+ # END: maintained by 'bazel run //tools/private:update_pip_deps'
)
# We need to do another use_extension call to expose the "pythons_hub"
@@ -47,3 +52,52 @@ use_repo(python, "pythons_hub")
# This call registers the Python toolchains.
register_toolchains("@pythons_hub//:all")
+
+# ===== DEV ONLY DEPS AND SETUP BELOW HERE =====
+bazel_dep(name = "stardoc", version = "0.6.2", dev_dependency = True, repo_name = "io_bazel_stardoc")
+bazel_dep(name = "rules_bazel_integration_test", version = "0.20.0", dev_dependency = True)
+
+dev_pip = use_extension(
+ "//python/extensions:pip.bzl",
+ "pip",
+ dev_dependency = True,
+)
+dev_pip.parse(
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-serializinghtml",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ ],
+ },
+ hub_name = "dev_pip",
+ python_version = "3.11",
+ requirements_lock = "//docs/sphinx:requirements.txt",
+)
+
+bazel_binaries = use_extension(
+ "@rules_bazel_integration_test//:extensions.bzl",
+ "bazel_binaries",
+ dev_dependency = True,
+)
+
+# Keep in sync with //:version.bzl
+bazel_binaries.local(
+ name = "self",
+ path = "tests/integration/bazel_from_env",
+)
+bazel_binaries.download(version = "6.4.0")
+bazel_binaries.download(version = "rolling")
+use_repo(
+ bazel_binaries,
+ "bazel_binaries",
+ # These don't appear necessary, but are reported as direct dependencies
+ # that should be use_repo()'d, so we add them as requested
+ "bazel_binaries_bazelisk",
+ "build_bazel_bazel_6_4_0",
+ "build_bazel_bazel_rolling",
+ "build_bazel_bazel_self",
+)
diff --git a/README.md b/README.md
index 69be729..546af97 100644
--- a/README.md
+++ b/README.md
@@ -1,346 +1,35 @@
# Python Rules for Bazel
-* Postsubmit [![Build status](https://badge.buildkite.com/0bcfe58b6f5741aacb09b12485969ba7a1205955a45b53e854.svg?branch=main)](https://buildkite.com/bazel/python-rules-python-postsubmit)
-* Postsubmit + Current Bazel Incompatible Flags [![Build status](https://badge.buildkite.com/219007166ab6a7798b22758e7ae3f3223001398ffb56a5ad2a.svg?branch=main)](https://buildkite.com/bazel/rules-python-plus-bazelisk-migrate)
+[![Build status](https://badge.buildkite.com/0bcfe58b6f5741aacb09b12485969ba7a1205955a45b53e854.svg?branch=main)](https://buildkite.com/bazel/rules-python-python)
## Overview
This repository is the home of the core Python rules -- `py_library`,
`py_binary`, `py_test`, `py_proto_library`, and related symbols that provide the basis for Python
-support in Bazel. It also contains package installation rules for integrating with PyPI and other package indices. Documentation lives in the
-[`docs/`](https://github.com/bazelbuild/rules_python/tree/main/docs)
-directory and in the
+support in Bazel. It also contains package installation rules for integrating with PyPI and other indices.
+
+Documentation for rules_python is at <https://rules-python.readthedocs.io> and in the
[Bazel Build Encyclopedia](https://docs.bazel.build/versions/master/be/python.html).
-Currently the core rules are bundled with Bazel itself, and the symbols in this
-repository are simple aliases. However, in the future the rules will be
-migrated to Starlark and debundled from Bazel. Therefore, the future-proof way
-to depend on Python rules is via this repository. See[`Migrating from the Bundled Rules`](#Migrating-from-the-bundled-rules) below.
+Examples live in the [examples](examples) directory.
+
+Currently, the core rules build into the Bazel binary, and the symbols in this
+repository are simple aliases. However, we are migrating the rules to Starlark and removing them from the Bazel binary. Therefore, the future-proof way to depend on Python rules is via this repository. See[`Migrating from the Bundled Rules`](#Migrating-from-the-bundled-rules) below.
The core rules are stable. Their implementation in Bazel is subject to Bazel's
[backward compatibility policy](https://docs.bazel.build/versions/master/backward-compatibility.html).
-Once they are fully migrated to rules_python, they may evolve at a different
-rate, but this repository will still follow
-[semantic versioning](https://semver.org).
+Once migrated to rules_python, they may evolve at a different
+rate, but this repository will still follow [semantic versioning](https://semver.org).
+
+The Bazel community maintains this repository. Neither Google nor the Bazel team provides support for the code. However, this repository is part of the test suite used to vet new Bazel releases. See [How to contribute](CONTRIBUTING.md) page for information on our development workflow.
-The package installation rules (`pip_install`, `pip_parse` etc.) are less stable. We may make breaking
-changes as they evolve.
+## Documentation
-This repository is maintained by the Bazel community. Neither Google, nor the
-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.
+For detailed documentation, see <https://rules-python.readthedocs.io>
-## `bzlmod` support
+## 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
-the older way of configuring bazel with a `WORKSPACE` file.
-
-### Using bzlmod
-
-NOTE: bzlmod support is still experimental; APIs subject to change.
-
-To import rules_python in your project, you first need to add it to your
-`MODULE.bazel` file, using the snippet provided in the
-[release you choose](https://github.com/bazelbuild/rules_python/releases).
-
-Once the dependency is added, a Python toolchain will be automatically
-registered and you'll be able to create runnable programs and tests.
-
-
-#### Toolchain registration with bzlmod
-
-NOTE: bzlmod support is still experimental; APIs subject to change.
-
-A default toolchain is automatically configured for by depending on
-`rules_python`. Note, however, the version used tracks the most recent Python
-release and will change often.
-
-If you want to register specific Python versions, then use
-`python.toolchain()` for each version you need:
-
-```starlark
-python = use_extension("@rules_python//python:extensions.bzl", "python")
-
-python.toolchain(
- python_version = "3.9",
-)
-```
-
-### Using pip with bzlmod
-
-NOTE: bzlmod support is still experimental; APIs subject to change.
-
-To use dependencies from PyPI, the `pip.parse()` extension is used to
-convert a requirements file into Bazel dependencies.
-
-```starlark
-python = use_extension("@rules_python//python/extensions:python.bzl", "python")
-python.toolchain(
- python_version = "3.9",
-)
-
-interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter")
-interpreter.install(
- name = "interpreter",
- python_name = "python_3_9",
-)
-use_repo(interpreter, "interpreter")
-
-pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
-pip.parse(
- hub_name = "pip",
- python_interpreter_target = "@interpreter//:python",
- requirements_lock = "//:requirements_lock.txt",
- requirements_windows = "//:requirements_windows.txt",
-)
-use_repo(pip, "pip")
-```
-
-For more documentation see the bzlmod examples under the [examples](examples) folder.
-
-### Using a WORKSPACE file
-
-To import rules_python in your project, you first need to add it to your
-`WORKSPACE` file, using the snippet provided in the
-[release you choose](https://github.com/bazelbuild/rules_python/releases)
-
-To depend on a particular unreleased version, you can do:
-
-```python
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-rules_python_version = "740825b7f74930c62f44af95c9a4c1bd428d2c53" # Latest @ 2021-06-23
-
-http_archive(
- name = "rules_python",
- # Bazel will print the proper value to add here during the first build.
- # sha256 = "FIXME",
- strip_prefix = "rules_python-{}".format(rules_python_version),
- url = "https://github.com/bazelbuild/rules_python/archive/{}.zip".format(rules_python_version),
-)
-```
-
-#### Toolchain registration
-
-To register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `WORKSPACE` file:
-
-```python
-load("@rules_python//python:repositories.bzl", "python_register_toolchains")
-
-python_register_toolchains(
- name = "python3_9",
- # Available versions are listed in @rules_python//python:versions.bzl.
- # We recommend using the same version your team is already standardized on.
- python_version = "3.9",
-)
-
-load("@python3_9//:defs.bzl", "interpreter")
-
-load("@rules_python//python:pip.bzl", "pip_parse")
-
-pip_parse(
- ...
- python_interpreter_target = interpreter,
- ...
-)
-```
-
-After registration, your Python targets will use the toolchain's interpreter during execution, but a system-installed interpreter
-is still used to 'bootstrap' Python targets (see https://github.com/bazelbuild/rules_python/issues/691).
-You may also find some quirks while using this toolchain. Please refer to [python-build-standalone documentation's _Quirks_ section](https://python-build-standalone.readthedocs.io/en/latest/quirks.html) for details.
-
-### Toolchain usage in other rules
-
-Python toolchains can be utilised in other bazel rules, such as `genrule()`, by adding the `toolchains=["@rules_python//python:current_py_toolchain"]` attribute. The path to the python interpreter can be obtained by using the `$(PYTHON2)` and `$(PYTHON3)` ["Make" Variables](https://bazel.build/reference/be/make-variables). See the [`test_current_py_toolchain`](tests/load_from_macro/BUILD.bazel) target for an example.
-
-
-### "Hello World"
-
-Once you've imported the rule set into your `WORKSPACE` using any of these
-methods, you can then load the core rules in your `BUILD` files with:
-
-``` python
-load("@rules_python//python:defs.bzl", "py_binary")
-
-py_binary(
- name = "main",
- srcs = ["main.py"],
-)
-```
-
-## Using the package installation rules
-
-Usage of the packaging rules involves two main steps.
-
-1. [Installing third_party packages](#installing-third_party-packages)
-2. [Using third_party packages as dependencies](#using-third_party-packages-as-dependencies)
-
-The package installation rules create two kinds of repositories: A central external repo that holds
-downloaded wheel files, and individual external repos for each wheel's extracted
-contents. Users only need to interact with the central external repo; the wheel repos
-are essentially an implementation detail. The central external repo provides a
-`WORKSPACE` macro to create the wheel repos, as well as a function, `requirement()`, for use in
-`BUILD` files that translates a pip package name into the label of a `py_library`
-target in the appropriate wheel repo.
-
-### Installing third_party packages
-
-#### Using bzlmod
-
-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
-pip.parse(
- hub_name = "my_deps",
- requirements_lock = "//:requirements_lock.txt",
-)
-
-use_repo(pip, "my_deps")
-```
-
-#### Using a WORKSPACE file
-
-To add pip dependencies to your `WORKSPACE`, load the `pip_parse` function, and call it to create the
-central external repo and individual wheel external repos.
-
-
-```python
-load("@rules_python//python:pip.bzl", "pip_parse")
-
-# Create a central repo that knows about the dependencies needed from
-# requirements_lock.txt.
-pip_parse(
- name = "my_deps",
- requirements_lock = "//path/to:requirements_lock.txt",
-)
-# Load the starlark macro which will define your dependencies.
-load("@my_deps//:requirements.bzl", "install_deps")
-# Call it to define repos for your requirements.
-install_deps()
-```
-
-#### pip rules
-
-Note that since `pip_parse` is a repository rule and therefore executes pip at WORKSPACE-evaluation time, Bazel has no
-information about the Python toolchain and cannot enforce that the interpreter
-used to invoke pip matches the interpreter used to run `py_binary` targets. By
-default, `pip_parse` uses the system command `"python3"`. This can be overridden by passing the
-`python_interpreter` attribute or `python_interpreter_target` attribute to `pip_parse`.
-
-You can have multiple `pip_parse`s in the same workspace. This will create multiple external repos that have no relation to one another, and may result in downloading the same wheels multiple times.
-
-As with any repository rule, if you would like to ensure that `pip_parse` is
-re-executed in order to pick up a non-hermetic change to your environment (e.g.,
-updating your system `python` interpreter), you can force it to re-execute by running
-`bazel sync --only [pip_parse name]`.
-
-Note: The `pip_install` rule is deprecated. `pip_parse` offers identical functionality and both `pip_install`
-and `pip_parse` now have the same implementation. The name `pip_install` may be removed in a future version of the rules.
-The maintainers have taken all reasonable efforts to faciliate a smooth transition, but some users of `pip_install` will
-need to replace their existing `requirements.txt` with a fully resolved set of dependencies using a tool such as
-`pip-tools` or the `compile_pip_requirements` repository rule.
-
-### Using third_party packages as dependencies
-
-Each extracted wheel repo contains a `py_library` target representing
-the wheel's contents. There are two ways to access this library. The
-first is using the `requirement()` function defined in the central
-repo's `//:requirements.bzl` file. This function maps a pip package
-name to a label:
-
-```python
-load("@my_deps//:requirements.bzl", "requirement")
-
-py_library(
- name = "mylib",
- srcs = ["mylib.py"],
- deps = [
- ":myotherlib",
- requirement("some_pip_dep"),
- requirement("another_pip_dep"),
- ]
-)
-```
-
-The reason `requirement()` exists is that the pattern for the labels,
-while not expected to change frequently, is not guaranteed to be
-stable. Using `requirement()` ensures that you do not have to refactor
-your `BUILD` files if the pattern changes.
-
-On the other hand, using `requirement()` has several drawbacks; see
-[this issue][requirements-drawbacks] for an enumeration. If you don't
-want to use `requirement()` then you can instead use the library
-labels directly. For `pip_parse` the labels are of the form
-
-```
-@{name}_{package}//:pkg
-```
-
-Here `name` is the `name` attribute that was passed to `pip_parse` and
-`package` is the pip package name with characters that are illegal in
-Bazel label names (e.g. `-`, `.`) replaced with `_`. If you need to
-update `name` from "old" to "new", then you can run the following
-buildozer command:
-
-```
-buildozer 'substitute deps @old_([^/]+)//:pkg @new_${1}//:pkg' //...:*
-```
-
-For `pip_install` the labels are instead of the form
-
-```
-@{name}//pypi__{package}
-```
-
-[requirements-drawbacks]: https://github.com/bazelbuild/rules_python/issues/414
-
-#### 'Extras' dependencies
-
-Any 'extras' specified in the requirements lock-file will be automatically added as transitive dependencies of the
-package. In the example above, you'd just put `requirement("useful_dep")`.
-
-### Consuming Wheel Dists Directly
-
-If you need to depend on the wheel dists themselves, for instance to pass them
-to some other packaging tool, you can get a handle to them with the `whl_requirement` macro. For example:
-
-```python
-filegroup(
- name = "whl_files",
- data = [
- whl_requirement("boto3"),
- ]
-)
-```
-
-## Migrating from the bundled rules
-
-The core rules are currently available in Bazel as built-in symbols, but this
-form is deprecated. Instead, you should depend on rules_python in your
-`WORKSPACE` file and load the Python rules from
-`@rules_python//python:defs.bzl`.
-
-A [buildifier](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md)
-fix is available to automatically migrate `BUILD` and `.bzl` files to add the
-appropriate `load()` statements and rewrite uses of `native.py_*`.
-
-```sh
-# Also consider using the -r flag to modify an entire workspace.
-buildifier --lint=fix --warnings=native-py <files>
-```
-
-Currently the `WORKSPACE` file needs to be updated manually as per [Getting
-started](#Getting-started) above.
-
-Note that Starlark-defined bundled symbols underneath
-`@bazel_tools//tools/python` are also deprecated. These are not yet rewritten
-by buildifier.
diff --git a/WORKSPACE b/WORKSPACE
index a833de8..5631dce 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -21,6 +21,22 @@ load("//:internal_deps.bzl", "rules_python_internal_deps")
rules_python_internal_deps()
+load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
+
+rules_jvm_external_deps()
+
+load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
+
+rules_jvm_external_setup()
+
+load("@io_bazel_stardoc//:deps.bzl", "stardoc_external_deps")
+
+stardoc_external_deps()
+
+load("@stardoc_maven//:defs.bzl", stardoc_pinned_maven_install = "pinned_maven_install")
+
+stardoc_pinned_maven_install()
+
load("//:internal_setup.bzl", "rules_python_internal_setup")
rules_python_internal_setup()
@@ -30,11 +46,11 @@ load("//python:versions.bzl", "MINOR_MAPPING")
python_register_multi_toolchains(
name = "python",
- default_version = MINOR_MAPPING.values()[-1],
+ default_version = MINOR_MAPPING.values()[-2],
python_versions = MINOR_MAPPING.values(),
)
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
# Used for Bazel CI
http_archive(
@@ -68,11 +84,13 @@ load("@rules_python_gazelle_plugin//:deps.bzl", _py_gazelle_deps = "gazelle_deps
# for python requirements.
_py_gazelle_deps()
+# This interpreter is used for various rules_python dev-time tools
+load("@python//3.11.6:defs.bzl", "interpreter")
+
#####################
# Install twine for our own runfiles wheel publishing.
# Eventually we might want to install twine automatically for users too, see:
# https://github.com/bazelbuild/rules_python/issues/1016.
-load("@python//3.11.1:defs.bzl", "interpreter")
load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
@@ -86,3 +104,44 @@ pip_parse(
load("@publish_deps//:requirements.bzl", "install_deps")
install_deps()
+
+#####################
+# Install sphinx for doc generation.
+
+pip_parse(
+ name = "dev_pip",
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-serializinghtml",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ ],
+ },
+ incompatible_generate_aliases = True,
+ python_interpreter_target = interpreter,
+ requirements_lock = "//docs/sphinx:requirements.txt",
+)
+
+load("@dev_pip//:requirements.bzl", docs_install_deps = "install_deps")
+
+docs_install_deps()
+
+# This wheel is purely here to validate the wheel extraction code. It's not
+# intended for anything else.
+http_file(
+ name = "wheel_for_testing",
+ downloaded_file_path = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+ sha256 = "0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2",
+ urls = [
+ "https://files.pythonhosted.org/packages/50/67/3e966d99a07d60a21a21d7ec016e9e4c2642a86fea251ec68677daf71d4d/numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+ ],
+)
+
+# rules_proto expects //external:python_headers to point at the python headers.
+bind(
+ name = "python_headers",
+ actual = "//python/cc:current_py_cc_headers",
+)
diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel
index 1fb4f81..c334fbc 100644
--- a/docs/BUILD.bazel
+++ b/docs/BUILD.bazel
@@ -13,175 +13,40 @@
# limitations under the License.
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
-load("@bazel_skylib//rules:write_file.bzl", "write_file")
-load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+# NOTE: Only public visibility for historical reasons.
+# This package is only for rules_python to generate its own docs.
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
-_DOCS = {
- "packaging": "//docs:packaging-docs",
- "pip": "//docs:pip-docs",
- "pip_repository": "//docs:pip-repository",
- "py_cc_toolchain": "//docs:py_cc_toolchain-docs",
- "py_cc_toolchain_info": "//docs:py_cc_toolchain_info-docs",
- "python": "//docs:core-docs",
-}
-
-# We define these bzl_library targets here rather than in the //python package
-# because they're only used for doc generation. This way, we avoid requiring
-# our users to depend on Skylib.
-
-bzl_library(
- name = "bazel_repo_tools",
- srcs = [
- "@bazel_tools//tools:bzl_srcs",
- ],
+# Temporary compatibility aliases for some other projects depending on the old
+# bzl_library targets.
+alias(
+ name = "defs",
+ actual = "//python:defs_bzl",
+ deprecation = "Use //python:defs_bzl instead; targets under //docs are internal.",
)
-bzl_library(
- name = "defs",
- srcs = [
- "//python:defs.bzl",
- "//python/private:reexports.bzl",
- ],
- deps = [
- ":bazel_repo_tools",
- "//python:defs_bzl",
- "//python/private:reexports_bzl",
- ],
+alias(
+ name = "bazel_repo_tools",
+ actual = "//python/private:bazel_tools_bzl",
+ deprecation = "Use @bazel_tools//tools:bzl_srcs instead; targets under //docs are internal.",
)
bzl_library(
name = "pip_install_bzl",
- srcs = [
- "//python:bzl",
- "//python/pip_install:bzl",
- ],
+ deprecation = "Use //python:pip_bzl or //python/pip_install:pip_repository_bzl instead; " +
+ "targets under //docs are internal.",
deps = [
- ":defs",
- "//:version.bzl",
+ "//python:pip_bzl",
+ "//python/pip_install:pip_repository_bzl",
],
)
-bzl_library(
+alias(
name = "requirements_parser_bzl",
- srcs = [
- "//python/pip_install:requirements_parser.bzl",
- ],
-)
-
-bzl_library(
- name = "packaging_bzl",
- srcs = [
- "//python:packaging.bzl",
- "//python/private:py_package.bzl",
- "//python/private:py_wheel.bzl",
- "//python/private:stamp.bzl",
- "//python/private:util.bzl",
- ],
- deps = [
- "//python/private:util_bzl",
- ],
-)
-
-# TODO: Stardoc does not guarantee consistent outputs accross platforms (Unix/Windows).
-# As a result we do not build or test docs on Windows.
-_NOT_WINDOWS = select({
- "@platforms//os:linux": [],
- "@platforms//os:macos": [],
- "//conditions:default": ["@platforms//:incompatible"],
-})
-
-stardoc(
- name = "core-docs",
- out = "python.md_",
- input = "//python:defs.bzl",
- target_compatible_with = _NOT_WINDOWS,
- deps = [":defs"],
-)
-
-stardoc(
- name = "pip-docs",
- out = "pip.md_",
- input = "//python:pip.bzl",
- target_compatible_with = _NOT_WINDOWS,
- deps = [
- ":bazel_repo_tools",
- ":pip_install_bzl",
- "@bazel_skylib//lib:versions",
- ],
-)
-
-stardoc(
- name = "pip-repository",
- out = "pip_repository.md_",
- input = "//python/pip_install:pip_repository.bzl",
- target_compatible_with = _NOT_WINDOWS,
- deps = [
- ":bazel_repo_tools",
- ":pip_install_bzl",
- ":requirements_parser_bzl",
- "@bazel_skylib//lib:versions",
- ],
-)
-
-stardoc(
- name = "packaging-docs",
- out = "packaging.md_",
- input = "//python:packaging.bzl",
- target_compatible_with = _NOT_WINDOWS,
- deps = [":packaging_bzl"],
-)
-
-stardoc(
- name = "py_cc_toolchain-docs",
- out = "py_cc_toolchain.md_",
- # NOTE: The public file isn't used as the input because it would document
- # the macro, which doesn't have the attribute documentation. The macro
- # doesn't do anything interesting to users, so bypass it to avoid having to
- # copy/paste all the rule's doc in the macro.
- input = "//python/private:py_cc_toolchain_rule.bzl",
- target_compatible_with = _NOT_WINDOWS,
- deps = ["//python/private:py_cc_toolchain_bzl"],
-)
-
-stardoc(
- name = "py_cc_toolchain_info-docs",
- out = "py_cc_toolchain_info.md_",
- input = "//python/cc:py_cc_toolchain_info.bzl",
- deps = ["//python/cc:py_cc_toolchain_info_bzl"],
-)
-
-[
- diff_test(
- name = "check_" + k,
- failure_message = "Please run: bazel run //docs:update",
- file1 = k + ".md",
- file2 = k + ".md_",
- target_compatible_with = _NOT_WINDOWS,
- )
- for k in _DOCS.keys()
-]
-
-write_file(
- name = "gen_update",
- out = "update.sh",
- content = [
- "#!/usr/bin/env bash",
- "cd $BUILD_WORKSPACE_DIRECTORY",
- ] + [
- "cp -fv bazel-bin/docs/{0}.md_ docs/{0}.md".format(k)
- for k in _DOCS.keys()
- ],
- target_compatible_with = _NOT_WINDOWS,
-)
-
-sh_binary(
- name = "update",
- srcs = ["update.sh"],
- data = _DOCS.values(),
- target_compatible_with = _NOT_WINDOWS,
+ actual = "//python/pip_install:pip_repository_bzl",
+ deprecation = "Use //python/pip_install:pip_repository_bzl instead; Both the requirements " +
+ "parser and targets under //docs are internal",
)
diff --git a/docs/packaging.md b/docs/packaging.md
deleted file mode 100755
index 0e8e110..0000000
--- a/docs/packaging.md
+++ /dev/null
@@ -1,211 +0,0 @@
-<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-
-Public API for for building wheels.
-
-<a id="py_package"></a>
-
-## py_package
-
-<pre>
-py_package(<a href="#py_package-name">name</a>, <a href="#py_package-deps">deps</a>, <a href="#py_package-packages">packages</a>)
-</pre>
-
-A rule to select all files in transitive dependencies of deps which
-belong to given set of Python packages.
-
-This rule is intended to be used as data dependency to py_wheel rule.
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="py_package-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="py_package-deps"></a>deps | - | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
-| <a id="py_package-packages"></a>packages | List of Python packages to include in the distribution. Sub-packages are automatically included. | List of strings | optional | <code>[]</code> |
-
-
-<a id="py_wheel_dist"></a>
-
-## py_wheel_dist
-
-<pre>
-py_wheel_dist(<a href="#py_wheel_dist-name">name</a>, <a href="#py_wheel_dist-out">out</a>, <a href="#py_wheel_dist-wheel">wheel</a>)
-</pre>
-
-Prepare a dist/ folder, following Python's packaging standard practice.
-
-See https://packaging.python.org/en/latest/tutorials/packaging-projects/#generating-distribution-archives
-which recommends a dist/ folder containing the wheel file(s), source distributions, etc.
-
-This also has the advantage that stamping information is included in the wheel's filename.
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="py_wheel_dist-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="py_wheel_dist-out"></a>out | name of the resulting directory | String | required | |
-| <a id="py_wheel_dist-wheel"></a>wheel | a [py_wheel rule](/docs/packaging.md#py_wheel_rule) | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-
-
-<a id="py_wheel_rule"></a>
-
-## py_wheel_rule
-
-<pre>
-py_wheel_rule(<a href="#py_wheel_rule-name">name</a>, <a href="#py_wheel_rule-abi">abi</a>, <a href="#py_wheel_rule-author">author</a>, <a href="#py_wheel_rule-author_email">author_email</a>, <a href="#py_wheel_rule-classifiers">classifiers</a>, <a href="#py_wheel_rule-console_scripts">console_scripts</a>, <a href="#py_wheel_rule-deps">deps</a>,
- <a href="#py_wheel_rule-description_content_type">description_content_type</a>, <a href="#py_wheel_rule-description_file">description_file</a>, <a href="#py_wheel_rule-distribution">distribution</a>, <a href="#py_wheel_rule-entry_points">entry_points</a>,
- <a href="#py_wheel_rule-extra_distinfo_files">extra_distinfo_files</a>, <a href="#py_wheel_rule-extra_requires">extra_requires</a>, <a href="#py_wheel_rule-homepage">homepage</a>, <a href="#py_wheel_rule-license">license</a>, <a href="#py_wheel_rule-platform">platform</a>, <a href="#py_wheel_rule-project_urls">project_urls</a>,
- <a href="#py_wheel_rule-python_requires">python_requires</a>, <a href="#py_wheel_rule-python_tag">python_tag</a>, <a href="#py_wheel_rule-requires">requires</a>, <a href="#py_wheel_rule-stamp">stamp</a>, <a href="#py_wheel_rule-strip_path_prefixes">strip_path_prefixes</a>, <a href="#py_wheel_rule-summary">summary</a>, <a href="#py_wheel_rule-version">version</a>)
-</pre>
-
-Internal rule used by the [py_wheel macro](/docs/packaging.md#py_wheel).
-
-These intentionally have the same name to avoid sharp edges with Bazel macros.
-For example, a `bazel query` for a user's `py_wheel` macro expands to `py_wheel` targets,
-in the way they expect.
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="py_wheel_rule-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="py_wheel_rule-abi"></a>abi | Python ABI tag. 'none' for pure-Python wheels. | String | optional | <code>"none"</code> |
-| <a id="py_wheel_rule-author"></a>author | A string specifying the author of the package. | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-author_email"></a>author_email | A string specifying the email address of the package author. | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-classifiers"></a>classifiers | A list of strings describing the categories for the package. For valid classifiers see https://pypi.org/classifiers | List of strings | optional | <code>[]</code> |
-| <a id="py_wheel_rule-console_scripts"></a>console_scripts | Deprecated console_script entry points, e.g. <code>{'main': 'examples.wheel.main:main'}</code>.<br><br>Deprecated: prefer the <code>entry_points</code> attribute, which supports <code>console_scripts</code> as well as other entry points. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
-| <a id="py_wheel_rule-deps"></a>deps | Targets to be included in the distribution.<br><br>The targets to package are usually <code>py_library</code> rules or filesets (for packaging data files).<br><br>Note it's usually better to package <code>py_library</code> targets and use <code>entry_points</code> attribute to specify <code>console_scripts</code> than to package <code>py_binary</code> rules. <code>py_binary</code> targets would wrap a executable script that tries to locate <code>.runfiles</code> directory which is not packaged in the wheel. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
-| <a id="py_wheel_rule-description_content_type"></a>description_content_type | The type of contents in description_file. If not provided, the type will be inferred from the extension of description_file. Also see https://packaging.python.org/en/latest/specifications/core-metadata/#description-content-type | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-description_file"></a>description_file | A file containing text describing the package. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="py_wheel_rule-distribution"></a>distribution | Name of the distribution.<br><br>This should match the project name onm PyPI. It's also the name that is used to refer to the package in other packages' dependencies.<br><br>Workspace status keys are expanded using <code>{NAME}</code> format, for example: - <code>distribution = "package.{CLASSIFIER}"</code> - <code>distribution = "{DISTRIBUTION}"</code><br><br>For the available keys, see https://bazel.build/docs/user-manual#workspace-status | String | required | |
-| <a id="py_wheel_rule-entry_points"></a>entry_points | entry_points, e.g. <code>{'console_scripts': ['main = examples.wheel.main:main']}</code>. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> List of strings</a> | optional | <code>{}</code> |
-| <a id="py_wheel_rule-extra_distinfo_files"></a>extra_distinfo_files | Extra files to add to distinfo directory in the archive. | <a href="https://bazel.build/rules/lib/dict">Dictionary: Label -> String</a> | optional | <code>{}</code> |
-| <a id="py_wheel_rule-extra_requires"></a>extra_requires | List of optional requirements for this package | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> List of strings</a> | optional | <code>{}</code> |
-| <a id="py_wheel_rule-homepage"></a>homepage | A string specifying the URL for the package homepage. | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-license"></a>license | A string specifying the license of the package. | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-platform"></a>platform | Supported platform. Use 'any' for pure-Python wheel.<br><br>If you have included platform-specific data, such as a .pyd or .so extension module, you will need to specify the platform in standard pip format. If you support multiple platforms, you can define platform constraints, then use a select() to specify the appropriate specifier, eg:<br><br><code> platform = select({ "//platforms:windows_x86_64": "win_amd64", "//platforms:macos_x86_64": "macosx_10_7_x86_64", "//platforms:linux_x86_64": "manylinux2014_x86_64", }) </code> | String | optional | <code>"any"</code> |
-| <a id="py_wheel_rule-project_urls"></a>project_urls | A string dict specifying additional browsable URLs for the project and corresponding labels, where label is the key and url is the value. e.g <code>{{"Bug Tracker": "http://bitbucket.org/tarek/distribute/issues/"}}</code> | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
-| <a id="py_wheel_rule-python_requires"></a>python_requires | Python versions required by this distribution, e.g. '&gt;=3.5,&lt;3.7' | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-python_tag"></a>python_tag | Supported Python version(s), eg <code>py3</code>, <code>cp35.cp36</code>, etc | String | optional | <code>"py3"</code> |
-| <a id="py_wheel_rule-requires"></a>requires | List of requirements for this package. See the section on [Declaring required dependency](https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html#declaring-dependencies) for details and examples of the format of this argument. | List of strings | optional | <code>[]</code> |
-| <a id="py_wheel_rule-stamp"></a>stamp | Whether to encode build information into the wheel. Possible values:<br><br>- <code>stamp = 1</code>: Always stamp the build information into the wheel, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it potentially kills remote caching for the target and any downstream actions that depend on it.<br><br>- <code>stamp = 0</code>: Always replace build information by constant values. This gives good build result caching.<br><br>- <code>stamp = -1</code>: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.<br><br>Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | <code>-1</code> |
-| <a id="py_wheel_rule-strip_path_prefixes"></a>strip_path_prefixes | path prefixes to strip from files added to the generated package | List of strings | optional | <code>[]</code> |
-| <a id="py_wheel_rule-summary"></a>summary | A one-line summary of what the distribution does | String | optional | <code>""</code> |
-| <a id="py_wheel_rule-version"></a>version | Version number of the package.<br><br>Note that this attribute supports stamp format strings as well as 'make variables'. For example: - <code>version = "1.2.3-{BUILD_TIMESTAMP}"</code> - <code>version = "{BUILD_EMBED_LABEL}"</code> - <code>version = "$(VERSION)"</code><br><br>Note that Bazel's output filename cannot include the stamp information, as outputs must be known during the analysis phase and the stamp data is available only during the action execution.<br><br>The [<code>py_wheel</code>](/docs/packaging.md#py_wheel) macro produces a <code>.dist</code>-suffix target which creates a <code>dist/</code> folder containing the wheel with the stamped name, suitable for publishing.<br><br>See [<code>py_wheel_dist</code>](/docs/packaging.md#py_wheel_dist) for more info. | String | required | |
-
-
-<a id="PyWheelInfo"></a>
-
-## PyWheelInfo
-
-<pre>
-PyWheelInfo(<a href="#PyWheelInfo-name_file">name_file</a>, <a href="#PyWheelInfo-wheel">wheel</a>)
-</pre>
-
-Information about a wheel produced by `py_wheel`
-
-**FIELDS**
-
-
-| Name | Description |
-| :------------- | :------------- |
-| <a id="PyWheelInfo-name_file"></a>name_file | File: A file containing the canonical name of the wheel (after stamping, if enabled). |
-| <a id="PyWheelInfo-wheel"></a>wheel | File: The wheel file itself. |
-
-
-<a id="py_wheel"></a>
-
-## py_wheel
-
-<pre>
-py_wheel(<a href="#py_wheel-name">name</a>, <a href="#py_wheel-twine">twine</a>, <a href="#py_wheel-publish_args">publish_args</a>, <a href="#py_wheel-kwargs">kwargs</a>)
-</pre>
-
-Builds a Python Wheel.
-
-Wheels are Python distribution format defined in https://www.python.org/dev/peps/pep-0427/.
-
-This macro packages a set of targets into a single wheel.
-It wraps the [py_wheel rule](#py_wheel_rule).
-
-Currently only pure-python wheels are supported.
-
-Examples:
-
-```python
-# Package some specific py_library targets, without their dependencies
-py_wheel(
- name = "minimal_with_py_library",
- # Package data. We're building "example_minimal_library-0.0.1-py3-none-any.whl"
- distribution = "example_minimal_library",
- python_tag = "py3",
- version = "0.0.1",
- deps = [
- "//examples/wheel/lib:module_with_data",
- "//examples/wheel/lib:simple_module",
- ],
-)
-
-# Use py_package to collect all transitive dependencies of a target,
-# selecting just the files within a specific python package.
-py_package(
- name = "example_pkg",
- # Only include these Python packages.
- packages = ["examples.wheel"],
- deps = [":main"],
-)
-
-py_wheel(
- name = "minimal_with_py_package",
- # Package data. We're building "example_minimal_package-0.0.1-py3-none-any.whl"
- distribution = "example_minimal_package",
- python_tag = "py3",
- version = "0.0.1",
- deps = [":example_pkg"],
-)
-```
-
-To publish the wheel to Pypi, the twine package is required.
-rules_python doesn't provide twine itself, see https://github.com/bazelbuild/rules_python/issues/1016
-However you can install it with pip_parse, just like we do in the WORKSPACE file in rules_python.
-
-Once you've installed twine, you can pass its label to the `twine` attribute of this macro,
-to get a "[name].publish" target.
-
-Example:
-
-```python
-py_wheel(
- name = "my_wheel",
- twine = "@publish_deps_twine//:pkg",
- ...
-)
-```
-
-Now you can run a command like the following, which publishes to https://test.pypi.org/
-
-```sh
-% TWINE_USERNAME=__token__ TWINE_PASSWORD=pypi-*** \
- bazel run --stamp --embed_label=1.2.4 -- \
- //path/to:my_wheel.publish --repository testpypi
-```
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="py_wheel-name"></a>name | A unique name for this target. | none |
-| <a id="py_wheel-twine"></a>twine | A label of the external location of the py_library target for twine | <code>None</code> |
-| <a id="py_wheel-publish_args"></a>publish_args | arguments passed to twine, e.g. ["--repository-url", "https://pypi.my.org/simple/"]. These are subject to make var expansion, as with the <code>args</code> attribute. Note that you can also pass additional args to the bazel run command as in the example above. | <code>[]</code> |
-| <a id="py_wheel-kwargs"></a>kwargs | other named parameters passed to the underlying [py_wheel rule](#py_wheel_rule) | none |
-
-
diff --git a/docs/pip.md b/docs/pip.md
deleted file mode 100644
index 6b96607..0000000
--- a/docs/pip.md
+++ /dev/null
@@ -1,273 +0,0 @@
-<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-
-Import pip requirements into Bazel.
-
-<a id="whl_library_alias"></a>
-
-## whl_library_alias
-
-<pre>
-whl_library_alias(<a href="#whl_library_alias-name">name</a>, <a href="#whl_library_alias-default_version">default_version</a>, <a href="#whl_library_alias-repo_mapping">repo_mapping</a>, <a href="#whl_library_alias-version_map">version_map</a>, <a href="#whl_library_alias-wheel_name">wheel_name</a>)
-</pre>
-
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="whl_library_alias-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="whl_library_alias-default_version"></a>default_version | - | String | required | |
-| <a id="whl_library_alias-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="whl_library_alias-version_map"></a>version_map | - | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="whl_library_alias-wheel_name"></a>wheel_name | - | String | required | |
-
-
-<a id="compile_pip_requirements"></a>
-
-## compile_pip_requirements
-
-<pre>
-compile_pip_requirements(<a href="#compile_pip_requirements-name">name</a>, <a href="#compile_pip_requirements-extra_args">extra_args</a>, <a href="#compile_pip_requirements-extra_deps">extra_deps</a>, <a href="#compile_pip_requirements-generate_hashes">generate_hashes</a>, <a href="#compile_pip_requirements-py_binary">py_binary</a>, <a href="#compile_pip_requirements-py_test">py_test</a>,
- <a href="#compile_pip_requirements-requirements_in">requirements_in</a>, <a href="#compile_pip_requirements-requirements_txt">requirements_txt</a>, <a href="#compile_pip_requirements-requirements_darwin">requirements_darwin</a>, <a href="#compile_pip_requirements-requirements_linux">requirements_linux</a>,
- <a href="#compile_pip_requirements-requirements_windows">requirements_windows</a>, <a href="#compile_pip_requirements-visibility">visibility</a>, <a href="#compile_pip_requirements-tags">tags</a>, <a href="#compile_pip_requirements-kwargs">kwargs</a>)
-</pre>
-
-Generates targets for managing pip dependencies with pip-compile.
-
-By default this rules generates a filegroup named "[name]" which can be included in the data
-of some other compile_pip_requirements rule that references these requirements
-(e.g. with `-r ../other/requirements.txt`).
-
-It also generates two targets for running pip-compile:
-
-- validate with `bazel test [name]_test`
-- update with `bazel run [name].update`
-
-If you are using a version control system, the requirements.txt generated by this rule should
-be checked into it to ensure that all developers/users have the same dependency versions.
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="compile_pip_requirements-name"></a>name | base name for generated targets, typically "requirements". | none |
-| <a id="compile_pip_requirements-extra_args"></a>extra_args | passed to pip-compile. | <code>[]</code> |
-| <a id="compile_pip_requirements-extra_deps"></a>extra_deps | extra dependencies passed to pip-compile. | <code>[]</code> |
-| <a id="compile_pip_requirements-generate_hashes"></a>generate_hashes | whether to put hashes in the requirements_txt file. | <code>True</code> |
-| <a id="compile_pip_requirements-py_binary"></a>py_binary | the py_binary rule to be used. | <code>&lt;function py_binary&gt;</code> |
-| <a id="compile_pip_requirements-py_test"></a>py_test | the py_test rule to be used. | <code>&lt;function py_test&gt;</code> |
-| <a id="compile_pip_requirements-requirements_in"></a>requirements_in | file expressing desired dependencies. | <code>None</code> |
-| <a id="compile_pip_requirements-requirements_txt"></a>requirements_txt | result of "compiling" the requirements.in file. | <code>None</code> |
-| <a id="compile_pip_requirements-requirements_darwin"></a>requirements_darwin | File of darwin specific resolve output to check validate if requirement.in has changes. | <code>None</code> |
-| <a id="compile_pip_requirements-requirements_linux"></a>requirements_linux | File of linux specific resolve output to check validate if requirement.in has changes. | <code>None</code> |
-| <a id="compile_pip_requirements-requirements_windows"></a>requirements_windows | File of windows specific resolve output to check validate if requirement.in has changes. | <code>None</code> |
-| <a id="compile_pip_requirements-visibility"></a>visibility | passed to both the _test and .update rules. | <code>["//visibility:private"]</code> |
-| <a id="compile_pip_requirements-tags"></a>tags | tagging attribute common to all build rules, passed to both the _test and .update rules. | <code>None</code> |
-| <a id="compile_pip_requirements-kwargs"></a>kwargs | other bazel attributes passed to the "_test" rule. | none |
-
-
-<a id="multi_pip_parse"></a>
-
-## multi_pip_parse
-
-<pre>
-multi_pip_parse(<a href="#multi_pip_parse-name">name</a>, <a href="#multi_pip_parse-default_version">default_version</a>, <a href="#multi_pip_parse-python_versions">python_versions</a>, <a href="#multi_pip_parse-python_interpreter_target">python_interpreter_target</a>,
- <a href="#multi_pip_parse-requirements_lock">requirements_lock</a>, <a href="#multi_pip_parse-kwargs">kwargs</a>)
-</pre>
-
-NOT INTENDED FOR DIRECT USE!
-
-This is intended to be used by the multi_pip_parse implementation in the template of the
-multi_toolchain_aliases repository rule.
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="multi_pip_parse-name"></a>name | the name of the multi_pip_parse repository. | none |
-| <a id="multi_pip_parse-default_version"></a>default_version | the default Python version. | none |
-| <a id="multi_pip_parse-python_versions"></a>python_versions | all Python toolchain versions currently registered. | none |
-| <a id="multi_pip_parse-python_interpreter_target"></a>python_interpreter_target | a dictionary which keys are Python versions and values are resolved host interpreters. | none |
-| <a id="multi_pip_parse-requirements_lock"></a>requirements_lock | a dictionary which keys are Python versions and values are locked requirements files. | none |
-| <a id="multi_pip_parse-kwargs"></a>kwargs | extra arguments passed to all wrapped pip_parse. | none |
-
-**RETURNS**
-
-The internal implementation of multi_pip_parse repository rule.
-
-
-<a id="package_annotation"></a>
-
-## package_annotation
-
-<pre>
-package_annotation(<a href="#package_annotation-additive_build_content">additive_build_content</a>, <a href="#package_annotation-copy_files">copy_files</a>, <a href="#package_annotation-copy_executables">copy_executables</a>, <a href="#package_annotation-data">data</a>, <a href="#package_annotation-data_exclude_glob">data_exclude_glob</a>,
- <a href="#package_annotation-srcs_exclude_glob">srcs_exclude_glob</a>)
-</pre>
-
-Annotations to apply to the BUILD file content from package generated from a `pip_repository` rule.
-
-[cf]: https://github.com/bazelbuild/bazel-skylib/blob/main/docs/copy_file_doc.md
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="package_annotation-additive_build_content"></a>additive_build_content | Raw text to add to the generated <code>BUILD</code> file of a package. | <code>None</code> |
-| <a id="package_annotation-copy_files"></a>copy_files | A mapping of <code>src</code> and <code>out</code> files for [@bazel_skylib//rules:copy_file.bzl][cf] | <code>{}</code> |
-| <a id="package_annotation-copy_executables"></a>copy_executables | A mapping of <code>src</code> and <code>out</code> files for [@bazel_skylib//rules:copy_file.bzl][cf]. Targets generated here will also be flagged as executable. | <code>{}</code> |
-| <a id="package_annotation-data"></a>data | A list of labels to add as <code>data</code> dependencies to the generated <code>py_library</code> target. | <code>[]</code> |
-| <a id="package_annotation-data_exclude_glob"></a>data_exclude_glob | A list of exclude glob patterns to add as <code>data</code> to the generated <code>py_library</code> target. | <code>[]</code> |
-| <a id="package_annotation-srcs_exclude_glob"></a>srcs_exclude_glob | A list of labels to add as <code>srcs</code> to the generated <code>py_library</code> target. | <code>[]</code> |
-
-**RETURNS**
-
-str: A json encoded string of the provided content.
-
-
-<a id="pip_install"></a>
-
-## pip_install
-
-<pre>
-pip_install(<a href="#pip_install-requirements">requirements</a>, <a href="#pip_install-name">name</a>, <a href="#pip_install-kwargs">kwargs</a>)
-</pre>
-
-Accepts a locked/compiled requirements file and installs the dependencies listed within.
-
-```python
-load("@rules_python//python:pip.bzl", "pip_install")
-
-pip_install(
- name = "pip_deps",
- requirements = ":requirements.txt",
-)
-
-load("@pip_deps//:requirements.bzl", "install_deps")
-
-install_deps()
-```
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="pip_install-requirements"></a>requirements | A 'requirements.txt' pip requirements file. | <code>None</code> |
-| <a id="pip_install-name"></a>name | A unique name for the created external repository (default 'pip'). | <code>"pip"</code> |
-| <a id="pip_install-kwargs"></a>kwargs | Additional arguments to the [<code>pip_repository</code>](./pip_repository.md) repository rule. | none |
-
-
-<a id="pip_parse"></a>
-
-## pip_parse
-
-<pre>
-pip_parse(<a href="#pip_parse-requirements">requirements</a>, <a href="#pip_parse-requirements_lock">requirements_lock</a>, <a href="#pip_parse-name">name</a>, <a href="#pip_parse-kwargs">kwargs</a>)
-</pre>
-
-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, see the "vendoring" section below.
-
-This macro wraps the [`pip_repository`](./pip_repository.md) rule that invokes `pip`.
-In your WORKSPACE file:
-
-```python
-load("@rules_python//python:pip.bzl", "pip_parse")
-
-pip_parse(
- name = "pip_deps",
- requirements_lock = ":requirements.txt",
-)
-
-load("@pip_deps//:requirements.bzl", "install_deps")
-
-install_deps()
-```
-
-You can then reference installed dependencies from a `BUILD` file with:
-
-```python
-load("@pip_deps//:requirements.bzl", "requirement")
-
-py_library(
- name = "bar",
- ...
- deps = [
- "//my/other:dep",
- requirement("requests"),
- requirement("numpy"),
- ],
-)
-```
-
-In addition to the `requirement` macro, which is used to access the generated `py_library`
-target generated from a package's wheel, The generated `requirements.bzl` file contains
-functionality for exposing [entry points][whl_ep] as `py_binary` targets as well.
-
-[whl_ep]: https://packaging.python.org/specifications/entry-points/
-
-```python
-load("@pip_deps//:requirements.bzl", "entry_point")
-
-alias(
- name = "pip-compile",
- actual = entry_point(
- pkg = "pip-tools",
- script = "pip-compile",
- ),
-)
-```
-
-Note that for packages whose name and script are the same, only the name of the package
-is needed when calling the `entry_point` macro.
-
-```python
-load("@pip_deps//:requirements.bzl", "entry_point")
-
-alias(
- name = "flake8",
- actual = entry_point("flake8"),
-)
-```
-
-## Vendoring the requirements.bzl file
-
-In some cases you may not want to generate the requirements.bzl file as a repository rule
-while Bazel is fetching dependencies. For example, if you produce a reusable Bazel module
-such as a ruleset, you may want to include the requirements.bzl file rather than make your users
-install the WORKSPACE setup to generate it.
-See https://github.com/bazelbuild/rules_python/issues/608
-
-This is the same workflow as Gazelle, which creates `go_repository` rules with
-[`update-repos`](https://github.com/bazelbuild/bazel-gazelle#update-repos)
-
-To do this, use the "write to source file" pattern documented in
-https://blog.aspect.dev/bazel-can-write-to-the-source-folder
-to put a copy of the generated requirements.bzl into your project.
-Then load the requirements.bzl file directly rather than from the generated repository.
-See the example in rules_python/examples/pip_parse_vendored.
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="pip_parse-requirements"></a>requirements | Deprecated. See requirements_lock. | <code>None</code> |
-| <a id="pip_parse-requirements_lock"></a>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'. Note that if your lockfile is platform-dependent, you can use the <code>requirements_[platform]</code> attributes. | <code>None</code> |
-| <a id="pip_parse-name"></a>name | The name of the generated repository. The generated repositories containing each requirement will be of the form <code>&lt;name&gt;_&lt;requirement-name&gt;</code>. | <code>"pip_parsed_deps"</code> |
-| <a id="pip_parse-kwargs"></a>kwargs | Additional arguments to the [<code>pip_repository</code>](./pip_repository.md) repository rule. | none |
-
-
diff --git a/docs/pip_repository.md b/docs/pip_repository.md
deleted file mode 100644
index 8536052..0000000
--- a/docs/pip_repository.md
+++ /dev/null
@@ -1,242 +0,0 @@
-<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-
-
-
-<a id="pip_hub_repository_bzlmod"></a>
-
-## pip_hub_repository_bzlmod
-
-<pre>
-pip_hub_repository_bzlmod(<a href="#pip_hub_repository_bzlmod-name">name</a>, <a href="#pip_hub_repository_bzlmod-repo_mapping">repo_mapping</a>, <a href="#pip_hub_repository_bzlmod-repo_name">repo_name</a>, <a href="#pip_hub_repository_bzlmod-whl_library_alias_names">whl_library_alias_names</a>)
-</pre>
-
-A rule for bzlmod mulitple pip repository creation. PRIVATE USE ONLY.
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="pip_hub_repository_bzlmod-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="pip_hub_repository_bzlmod-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="pip_hub_repository_bzlmod-repo_name"></a>repo_name | The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name. | String | required | |
-| <a id="pip_hub_repository_bzlmod-whl_library_alias_names"></a>whl_library_alias_names | The list of whl alias that we use to build aliases and the whl names | List of strings | required | |
-
-
-<a id="pip_repository"></a>
-
-## pip_repository
-
-<pre>
-pip_repository(<a href="#pip_repository-name">name</a>, <a href="#pip_repository-annotations">annotations</a>, <a href="#pip_repository-download_only">download_only</a>, <a href="#pip_repository-enable_implicit_namespace_pkgs">enable_implicit_namespace_pkgs</a>, <a href="#pip_repository-environment">environment</a>,
- <a href="#pip_repository-extra_pip_args">extra_pip_args</a>, <a href="#pip_repository-incompatible_generate_aliases">incompatible_generate_aliases</a>, <a href="#pip_repository-isolated">isolated</a>, <a href="#pip_repository-pip_data_exclude">pip_data_exclude</a>,
- <a href="#pip_repository-python_interpreter">python_interpreter</a>, <a href="#pip_repository-python_interpreter_target">python_interpreter_target</a>, <a href="#pip_repository-quiet">quiet</a>, <a href="#pip_repository-repo_mapping">repo_mapping</a>, <a href="#pip_repository-repo_prefix">repo_prefix</a>,
- <a href="#pip_repository-requirements_darwin">requirements_darwin</a>, <a href="#pip_repository-requirements_linux">requirements_linux</a>, <a href="#pip_repository-requirements_lock">requirements_lock</a>, <a href="#pip_repository-requirements_windows">requirements_windows</a>,
- <a href="#pip_repository-timeout">timeout</a>)
-</pre>
-
-A rule for importing `requirements.txt` dependencies into Bazel.
-
-This rule imports a `requirements.txt` file and generates a new
-`requirements.bzl` file. This is used via the `WORKSPACE` pattern:
-
-```python
-pip_repository(
- name = "foo",
- requirements = ":requirements.txt",
-)
-```
-
-You can then reference imported dependencies from your `BUILD` file with:
-
-```python
-load("@foo//:requirements.bzl", "requirement")
-py_library(
- name = "bar",
- ...
- deps = [
- "//my/other:dep",
- requirement("requests"),
- requirement("numpy"),
- ],
-)
-```
-
-Or alternatively:
-```python
-load("@foo//:requirements.bzl", "all_requirements")
-py_binary(
- name = "baz",
- ...
- deps = [
- ":foo",
- ] + all_requirements,
-)
-```
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="pip_repository-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="pip_repository-annotations"></a>annotations | Optional annotations to apply to packages | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
-| <a id="pip_repository-download_only"></a>download_only | Whether to use "pip download" instead of "pip wheel". Disables building wheels from source, but allows use of --platform, --python-version, --implementation, and --abi in --extra_pip_args to download wheels for a different platform from the host platform. | Boolean | optional | <code>False</code> |
-| <a id="pip_repository-enable_implicit_namespace_pkgs"></a>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 <code>legacy_create_init=False</code> or the global Bazel option <code>--incompatible_default_to_explicit_init_py</code> to prevent <code>__init__.py</code> being automatically generated in every directory.<br><br>This option is required to support some packages which cannot handle the conversion to pkg-util style. | Boolean | optional | <code>False</code> |
-| <a id="pip_repository-environment"></a>environment | Environment variables to set in the pip subprocess. Can be used to set common variables such as <code>http_proxy</code>, <code>https_proxy</code> and <code>no_proxy</code> Note that pip is run with "--isolated" on the CLI so <code>PIP_&lt;VAR&gt;_&lt;NAME&gt;</code> style env vars are ignored, but env vars that control requests and urllib3 can be passed. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
-| <a id="pip_repository-extra_pip_args"></a>extra_pip_args | Extra arguments to pass on to pip. Must not contain spaces. | List of strings | optional | <code>[]</code> |
-| <a id="pip_repository-incompatible_generate_aliases"></a>incompatible_generate_aliases | Allow generating aliases '@pip//&lt;pkg&gt;' -&gt; '@pip_&lt;pkg&gt;//:pkg'. | Boolean | optional | <code>False</code> |
-| <a id="pip_repository-isolated"></a>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 <code>RULES_PYTHON_PIP_ISOLATED</code> environment variable can be used to control this flag. | Boolean | optional | <code>True</code> |
-| <a id="pip_repository-pip_data_exclude"></a>pip_data_exclude | Additional data exclusion parameters to add to the pip packages BUILD file. | List of strings | optional | <code>[]</code> |
-| <a id="pip_repository-python_interpreter"></a>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 <code>PATH</code> environment variable. If no value is set <code>python3</code> is defaulted for Unix systems and <code>python.exe</code> for Windows. | String | optional | <code>""</code> |
-| <a id="pip_repository-python_interpreter_target"></a>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". | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository-quiet"></a>quiet | If True, suppress printing stdout and stderr output to the terminal. | Boolean | optional | <code>True</code> |
-| <a id="pip_repository-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="pip_repository-repo_prefix"></a>repo_prefix | Prefix for the generated packages will be of the form <code>@&lt;prefix&gt;&lt;sanitized-package-name&gt;//...</code> | String | optional | <code>""</code> |
-| <a id="pip_repository-requirements_darwin"></a>requirements_darwin | Override the requirements_lock attribute when the host platform is Mac OS | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository-requirements_linux"></a>requirements_linux | Override the requirements_lock attribute when the host platform is Linux | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository-requirements_lock"></a>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'. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository-requirements_windows"></a>requirements_windows | Override the requirements_lock attribute when the host platform is Windows | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository-timeout"></a>timeout | Timeout (in seconds) on the rule's execution duration. | Integer | optional | <code>600</code> |
-
-
-<a id="pip_repository_bzlmod"></a>
-
-## pip_repository_bzlmod
-
-<pre>
-pip_repository_bzlmod(<a href="#pip_repository_bzlmod-name">name</a>, <a href="#pip_repository_bzlmod-repo_mapping">repo_mapping</a>, <a href="#pip_repository_bzlmod-repo_name">repo_name</a>, <a href="#pip_repository_bzlmod-requirements_darwin">requirements_darwin</a>, <a href="#pip_repository_bzlmod-requirements_linux">requirements_linux</a>,
- <a href="#pip_repository_bzlmod-requirements_lock">requirements_lock</a>, <a href="#pip_repository_bzlmod-requirements_windows">requirements_windows</a>)
-</pre>
-
-A rule for bzlmod pip_repository creation. Intended for private use only.
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="pip_repository_bzlmod-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="pip_repository_bzlmod-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="pip_repository_bzlmod-repo_name"></a>repo_name | The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name | String | required | |
-| <a id="pip_repository_bzlmod-requirements_darwin"></a>requirements_darwin | Override the requirements_lock attribute when the host platform is Mac OS | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository_bzlmod-requirements_linux"></a>requirements_linux | Override the requirements_lock attribute when the host platform is Linux | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository_bzlmod-requirements_lock"></a>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'. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="pip_repository_bzlmod-requirements_windows"></a>requirements_windows | Override the requirements_lock attribute when the host platform is Windows | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-
-
-<a id="whl_library"></a>
-
-## whl_library
-
-<pre>
-whl_library(<a href="#whl_library-name">name</a>, <a href="#whl_library-annotation">annotation</a>, <a href="#whl_library-download_only">download_only</a>, <a href="#whl_library-enable_implicit_namespace_pkgs">enable_implicit_namespace_pkgs</a>, <a href="#whl_library-environment">environment</a>,
- <a href="#whl_library-extra_pip_args">extra_pip_args</a>, <a href="#whl_library-isolated">isolated</a>, <a href="#whl_library-pip_data_exclude">pip_data_exclude</a>, <a href="#whl_library-python_interpreter">python_interpreter</a>, <a href="#whl_library-python_interpreter_target">python_interpreter_target</a>,
- <a href="#whl_library-quiet">quiet</a>, <a href="#whl_library-repo">repo</a>, <a href="#whl_library-repo_mapping">repo_mapping</a>, <a href="#whl_library-repo_prefix">repo_prefix</a>, <a href="#whl_library-requirement">requirement</a>, <a href="#whl_library-timeout">timeout</a>)
-</pre>
-
-
-Download and extracts a single wheel based into a bazel repo based on the requirement string passed in.
-Instantiated from pip_repository and inherits config options from there.
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="whl_library-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="whl_library-annotation"></a>annotation | Optional json encoded file containing annotation to apply to the extracted wheel. See <code>package_annotation</code> | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="whl_library-download_only"></a>download_only | Whether to use "pip download" instead of "pip wheel". Disables building wheels from source, but allows use of --platform, --python-version, --implementation, and --abi in --extra_pip_args to download wheels for a different platform from the host platform. | Boolean | optional | <code>False</code> |
-| <a id="whl_library-enable_implicit_namespace_pkgs"></a>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 <code>legacy_create_init=False</code> or the global Bazel option <code>--incompatible_default_to_explicit_init_py</code> to prevent <code>__init__.py</code> being automatically generated in every directory.<br><br>This option is required to support some packages which cannot handle the conversion to pkg-util style. | Boolean | optional | <code>False</code> |
-| <a id="whl_library-environment"></a>environment | Environment variables to set in the pip subprocess. Can be used to set common variables such as <code>http_proxy</code>, <code>https_proxy</code> and <code>no_proxy</code> Note that pip is run with "--isolated" on the CLI so <code>PIP_&lt;VAR&gt;_&lt;NAME&gt;</code> style env vars are ignored, but env vars that control requests and urllib3 can be passed. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
-| <a id="whl_library-extra_pip_args"></a>extra_pip_args | Extra arguments to pass on to pip. Must not contain spaces. | List of strings | optional | <code>[]</code> |
-| <a id="whl_library-isolated"></a>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 <code>RULES_PYTHON_PIP_ISOLATED</code> environment variable can be used to control this flag. | Boolean | optional | <code>True</code> |
-| <a id="whl_library-pip_data_exclude"></a>pip_data_exclude | Additional data exclusion parameters to add to the pip packages BUILD file. | List of strings | optional | <code>[]</code> |
-| <a id="whl_library-python_interpreter"></a>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 <code>PATH</code> environment variable. If no value is set <code>python3</code> is defaulted for Unix systems and <code>python.exe</code> for Windows. | String | optional | <code>""</code> |
-| <a id="whl_library-python_interpreter_target"></a>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". | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
-| <a id="whl_library-quiet"></a>quiet | If True, suppress printing stdout and stderr output to the terminal. | Boolean | optional | <code>True</code> |
-| <a id="whl_library-repo"></a>repo | Pointer to parent repo name. Used to make these rules rerun if the parent repo changes. | String | required | |
-| <a id="whl_library-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="whl_library-repo_prefix"></a>repo_prefix | Prefix for the generated packages will be of the form <code>@&lt;prefix&gt;&lt;sanitized-package-name&gt;//...</code> | String | optional | <code>""</code> |
-| <a id="whl_library-requirement"></a>requirement | Python requirement string describing the package to make available | String | required | |
-| <a id="whl_library-timeout"></a>timeout | Timeout (in seconds) on the rule's execution duration. | Integer | optional | <code>600</code> |
-
-
-<a id="locked_requirements_label"></a>
-
-## locked_requirements_label
-
-<pre>
-locked_requirements_label(<a href="#locked_requirements_label-ctx">ctx</a>, <a href="#locked_requirements_label-attr">attr</a>)
-</pre>
-
-Get the preferred label for a locked requirements file based on platform.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="locked_requirements_label-ctx"></a>ctx | repository or module context | none |
-| <a id="locked_requirements_label-attr"></a>attr | attributes for the repo rule or tag extension | none |
-
-**RETURNS**
-
-Label
-
-
-<a id="package_annotation"></a>
-
-## package_annotation
-
-<pre>
-package_annotation(<a href="#package_annotation-additive_build_content">additive_build_content</a>, <a href="#package_annotation-copy_files">copy_files</a>, <a href="#package_annotation-copy_executables">copy_executables</a>, <a href="#package_annotation-data">data</a>, <a href="#package_annotation-data_exclude_glob">data_exclude_glob</a>,
- <a href="#package_annotation-srcs_exclude_glob">srcs_exclude_glob</a>)
-</pre>
-
-Annotations to apply to the BUILD file content from package generated from a `pip_repository` rule.
-
-[cf]: https://github.com/bazelbuild/bazel-skylib/blob/main/docs/copy_file_doc.md
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="package_annotation-additive_build_content"></a>additive_build_content | Raw text to add to the generated <code>BUILD</code> file of a package. | <code>None</code> |
-| <a id="package_annotation-copy_files"></a>copy_files | A mapping of <code>src</code> and <code>out</code> files for [@bazel_skylib//rules:copy_file.bzl][cf] | <code>{}</code> |
-| <a id="package_annotation-copy_executables"></a>copy_executables | A mapping of <code>src</code> and <code>out</code> files for [@bazel_skylib//rules:copy_file.bzl][cf]. Targets generated here will also be flagged as executable. | <code>{}</code> |
-| <a id="package_annotation-data"></a>data | A list of labels to add as <code>data</code> dependencies to the generated <code>py_library</code> target. | <code>[]</code> |
-| <a id="package_annotation-data_exclude_glob"></a>data_exclude_glob | A list of exclude glob patterns to add as <code>data</code> to the generated <code>py_library</code> target. | <code>[]</code> |
-| <a id="package_annotation-srcs_exclude_glob"></a>srcs_exclude_glob | A list of labels to add as <code>srcs</code> to the generated <code>py_library</code> target. | <code>[]</code> |
-
-**RETURNS**
-
-str: A json encoded string of the provided content.
-
-
-<a id="use_isolated"></a>
-
-## use_isolated
-
-<pre>
-use_isolated(<a href="#use_isolated-ctx">ctx</a>, <a href="#use_isolated-attr">attr</a>)
-</pre>
-
-Determine whether or not to pass the pip `--isolated` flag to the pip invocation.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="use_isolated-ctx"></a>ctx | repository or module context | none |
-| <a id="use_isolated-attr"></a>attr | attributes for the repo rule or tag extension | none |
-
-**RETURNS**
-
-True if --isolated should be passed
-
-
diff --git a/docs/py_cc_toolchain.md b/docs/py_cc_toolchain.md
deleted file mode 100644
index 3a59ea9..0000000
--- a/docs/py_cc_toolchain.md
+++ /dev/null
@@ -1,32 +0,0 @@
-<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-
-Implementation of py_cc_toolchain rule.
-
-NOTE: This is a beta-quality feature. APIs subject to change until
-https://github.com/bazelbuild/rules_python/issues/824 is considered done.
-
-
-<a id="py_cc_toolchain"></a>
-
-## py_cc_toolchain
-
-<pre>
-py_cc_toolchain(<a href="#py_cc_toolchain-name">name</a>, <a href="#py_cc_toolchain-headers">headers</a>, <a href="#py_cc_toolchain-python_version">python_version</a>)
-</pre>
-
-A toolchain for a Python runtime's C/C++ information (e.g. headers)
-
-This rule carries information about the C/C++ side of a Python runtime, e.g.
-headers, shared libraries, etc.
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="py_cc_toolchain-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="py_cc_toolchain-headers"></a>headers | Target that provides the Python headers. Typically this is a cc_library target. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
-| <a id="py_cc_toolchain-python_version"></a>python_version | The Major.minor Python version, e.g. 3.11 | String | required | |
-
-
diff --git a/docs/py_cc_toolchain_info.md b/docs/py_cc_toolchain_info.md
deleted file mode 100644
index 4e59a78..0000000
--- a/docs/py_cc_toolchain_info.md
+++ /dev/null
@@ -1,27 +0,0 @@
-<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-
-Provider for C/C++ information about the Python runtime.
-
-NOTE: This is a beta-quality feature. APIs subject to change until
-https://github.com/bazelbuild/rules_python/issues/824 is considered done.
-
-
-<a id="PyCcToolchainInfo"></a>
-
-## PyCcToolchainInfo
-
-<pre>
-PyCcToolchainInfo(<a href="#PyCcToolchainInfo-headers">headers</a>, <a href="#PyCcToolchainInfo-python_version">python_version</a>)
-</pre>
-
-C/C++ information about the Python runtime.
-
-**FIELDS**
-
-
-| Name | Description |
-| :------------- | :------------- |
-| <a id="PyCcToolchainInfo-headers"></a>headers | (struct) Information about the header files, with fields: * providers_map: a dict of string to provider instances. The key should be a fully qualified name (e.g. <code>@rules_foo//bar:baz.bzl#MyInfo</code>) of the provider to uniquely identify its type.<br><br> The following keys are always present: * CcInfo: the CcInfo provider instance for the headers. * DefaultInfo: the DefaultInfo provider instance for the headers.<br><br> A map is used to allow additional providers from the originating headers target (typically a <code>cc_library</code>) to be propagated to consumers (directly exposing a Target object can cause memory issues and is an anti-pattern).<br><br> When consuming this map, it's suggested to use <code>providers_map.values()</code> to return all providers; or copy the map and filter out or replace keys as appropriate. Note that any keys begining with <code>_</code> (underscore) are considered private and should be forward along as-is (this better allows e.g. <code>:current_py_cc_headers</code> to act as the underlying headers target it represents). |
-| <a id="PyCcToolchainInfo-python_version"></a>python_version | (str) The Python Major.Minor version. |
-
-
diff --git a/docs/python.md b/docs/python.md
deleted file mode 100755
index e42375a..0000000
--- a/docs/python.md
+++ /dev/null
@@ -1,227 +0,0 @@
-<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-
-Core rules for building Python projects.
-
-<a id="current_py_toolchain"></a>
-
-## current_py_toolchain
-
-<pre>
-current_py_toolchain(<a href="#current_py_toolchain-name">name</a>)
-</pre>
-
-
- This rule exists so that the current python toolchain can be used in the `toolchains` attribute of
- other rules, such as genrule. It allows exposing a python toolchain after toolchain resolution has
- happened, to a rule which expects a concrete implementation of a toolchain, rather than a
- toolchain_type which could be resolved to that toolchain.
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="current_py_toolchain-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-
-
-<a id="py_import"></a>
-
-## py_import
-
-<pre>
-py_import(<a href="#py_import-name">name</a>, <a href="#py_import-deps">deps</a>, <a href="#py_import-srcs">srcs</a>)
-</pre>
-
-This rule allows the use of Python packages as dependencies.
-
- It imports the given `.egg` file(s), which might be checked in source files,
- fetched externally as with `http_file`, or produced as outputs of other rules.
-
- It may be used like a `py_library`, in the `deps` of other Python rules.
-
- This is similar to [java_import](https://docs.bazel.build/versions/master/be/java.html#java_import).
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="py_import-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="py_import-deps"></a>deps | The list of other libraries to be linked in to the binary target. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
-| <a id="py_import-srcs"></a>srcs | The list of Python package files provided to Python targets that depend on this target. Note that currently only the .egg format is accepted. For .whl files, try the whl_library rule. We accept contributions to extend py_import to handle .whl. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
-
-
-<a id="py_binary"></a>
-
-## py_binary
-
-<pre>
-py_binary(<a href="#py_binary-attrs">attrs</a>)
-</pre>
-
-See the Bazel core [py_binary](https://docs.bazel.build/versions/master/be/python.html#py_binary) documentation.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="py_binary-attrs"></a>attrs | Rule attributes | none |
-
-
-<a id="py_library"></a>
-
-## py_library
-
-<pre>
-py_library(<a href="#py_library-attrs">attrs</a>)
-</pre>
-
-See the Bazel core [py_library](https://docs.bazel.build/versions/master/be/python.html#py_library) documentation.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="py_library-attrs"></a>attrs | Rule attributes | none |
-
-
-<a id="py_runtime"></a>
-
-## py_runtime
-
-<pre>
-py_runtime(<a href="#py_runtime-attrs">attrs</a>)
-</pre>
-
-See the Bazel core [py_runtime](https://docs.bazel.build/versions/master/be/python.html#py_runtime) documentation.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="py_runtime-attrs"></a>attrs | Rule attributes | none |
-
-
-<a id="py_runtime_pair"></a>
-
-## py_runtime_pair
-
-<pre>
-py_runtime_pair(<a href="#py_runtime_pair-name">name</a>, <a href="#py_runtime_pair-py2_runtime">py2_runtime</a>, <a href="#py_runtime_pair-py3_runtime">py3_runtime</a>, <a href="#py_runtime_pair-attrs">attrs</a>)
-</pre>
-
-A toolchain rule for Python.
-
-This used to wrap up to two Python runtimes, one for Python 2 and one for Python 3.
-However, Python 2 is no longer supported, so it now only wraps a single Python 3
-runtime.
-
-Usually the wrapped runtimes are declared using the `py_runtime` rule, but any
-rule returning a `PyRuntimeInfo` provider may be used.
-
-This rule returns a `platform_common.ToolchainInfo` provider with the following
-schema:
-
-```python
-platform_common.ToolchainInfo(
- py2_runtime = None,
- py3_runtime = &lt;PyRuntimeInfo or None&gt;,
-)
-```
-
-Example usage:
-
-```python
-# In your BUILD file...
-
-load("@rules_python//python:defs.bzl", "py_runtime_pair")
-
-py_runtime(
- name = "my_py3_runtime",
- interpreter_path = "/system/python3",
- python_version = "PY3",
-)
-
-py_runtime_pair(
- name = "my_py_runtime_pair",
- py3_runtime = ":my_py3_runtime",
-)
-
-toolchain(
- name = "my_toolchain",
- target_compatible_with = &lt;...&gt;,
- toolchain = ":my_py_runtime_pair",
- toolchain_type = "@rules_python//python:toolchain_type",
-)
-```
-
-```python
-# In your WORKSPACE...
-
-register_toolchains("//my_pkg:my_toolchain")
-```
-
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="py_runtime_pair-name"></a>name | str, the name of the target | none |
-| <a id="py_runtime_pair-py2_runtime"></a>py2_runtime | optional Label; must be unset or None; an error is raised otherwise. | <code>None</code> |
-| <a id="py_runtime_pair-py3_runtime"></a>py3_runtime | Label; a target with <code>PyRuntimeInfo</code> for Python 3. | <code>None</code> |
-| <a id="py_runtime_pair-attrs"></a>attrs | Extra attrs passed onto the native rule | none |
-
-
-<a id="py_test"></a>
-
-## py_test
-
-<pre>
-py_test(<a href="#py_test-attrs">attrs</a>)
-</pre>
-
-See the Bazel core [py_test](https://docs.bazel.build/versions/master/be/python.html#py_test) documentation.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="py_test-attrs"></a>attrs | Rule attributes | none |
-
-
-<a id="find_requirements"></a>
-
-## find_requirements
-
-<pre>
-find_requirements(<a href="#find_requirements-name">name</a>)
-</pre>
-
-The aspect definition. Can be invoked on the command line as
-
- bazel build //pkg:my_py_binary_target --aspects=@rules_python//python:defs.bzl%find_requirements --output_groups=pyversioninfo
-
-
-**ASPECT ATTRIBUTES**
-
-
-| Name | Type |
-| :------------- | :------------- |
-| deps| String |
-
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="find_requirements-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-
-
diff --git a/docs/sphinx/BUILD.bazel b/docs/sphinx/BUILD.bazel
new file mode 100644
index 0000000..8912f2c
--- /dev/null
+++ b/docs/sphinx/BUILD.bazel
@@ -0,0 +1,123 @@
+# 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.
+
+load("@dev_pip//:requirements.bzl", "requirement")
+load("//python:pip.bzl", "compile_pip_requirements")
+load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
+load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER") # buildifier: disable=bzl-visibility
+load("//sphinxdocs:readthedocs.bzl", "readthedocs_install")
+load("//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs", "sphinx_inventory")
+load("//sphinxdocs:sphinx_stardoc.bzl", "sphinx_stardocs")
+
+# We only build for Linux and Mac because:
+# 1. The actual doc process only runs on Linux
+# 2. Mac is a common development platform, and is close enough to Linux
+# it's feasible to make work.
+# Making CI happy under Windows is too much of a headache, though, so we don't
+# bother with that.
+_TARGET_COMPATIBLE_WITH = select({
+ "@platforms//os:linux": [],
+ "@platforms//os:macos": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+})
+
+# See README.md for instructions. Short version:
+# * `bazel run //docs/sphinx:docs.serve` in a separate terminal
+# * `ibazel build //docs/sphinx:docs` to automatically rebuild docs
+sphinx_docs(
+ name = "docs",
+ srcs = [
+ ":bazel_inventory",
+ ":bzl_api_docs",
+ ] + glob(
+ include = [
+ "*.md",
+ "**/*.md",
+ "_static/**",
+ "_includes/**",
+ ],
+ exclude = [
+ "README.md",
+ "_*",
+ "*.inv*",
+ ],
+ ),
+ config = "conf.py",
+ formats = [
+ "html",
+ ],
+ renamed_srcs = {
+ "//:CHANGELOG.md": "changelog.md",
+ "//:CONTRIBUTING.md": "contributing.md",
+ },
+ sphinx = ":sphinx-build",
+ strip_prefix = package_name() + "/",
+ tags = ["docs"],
+ target_compatible_with = _TARGET_COMPATIBLE_WITH,
+)
+
+sphinx_inventory(
+ name = "bazel_inventory",
+ src = "bazel_inventory.txt",
+)
+
+sphinx_stardocs(
+ name = "bzl_api_docs",
+ docs = {
+ "api/cc/py_cc_toolchain.md": dict(
+ dep = "//python/private:py_cc_toolchain_bzl",
+ input = "//python/private:py_cc_toolchain_rule.bzl",
+ public_load_path = "//python/cc:py_cc_toolchain.bzl",
+ ),
+ "api/cc/py_cc_toolchain_info.md": "//python/cc:py_cc_toolchain_info_bzl",
+ "api/defs.md": "//python:defs_bzl",
+ "api/entry_points/py_console_script_binary.md": "//python/entry_points:py_console_script_binary_bzl",
+ "api/packaging.md": "//python:packaging_bzl",
+ "api/pip.md": "//python:pip_bzl",
+ } | ({
+ # Bazel 6 + Stardoc isn't able to parse something about the python bzlmod extension
+ "api/extensions/python.md": "//python/extensions:python_bzl",
+ } if IS_BAZEL_7_OR_HIGHER else {}) | ({
+ # This depends on @pythons_hub, which is only created under bzlmod,
+ "api/extensions/pip.md": "//python/extensions:pip_bzl",
+ } if IS_BAZEL_7_OR_HIGHER and BZLMOD_ENABLED else {}),
+ footer = "_stardoc_footer.md",
+ tags = ["docs"],
+ target_compatible_with = _TARGET_COMPATIBLE_WITH,
+)
+
+readthedocs_install(
+ name = "readthedocs_install",
+ docs = [":docs"],
+ target_compatible_with = _TARGET_COMPATIBLE_WITH,
+)
+
+sphinx_build_binary(
+ name = "sphinx-build",
+ target_compatible_with = _TARGET_COMPATIBLE_WITH,
+ deps = [
+ requirement("sphinx"),
+ requirement("sphinx_rtd_theme"),
+ requirement("myst_parser"),
+ requirement("readthedocs_sphinx_ext"),
+ ],
+)
+
+# Run bazel run //docs/sphinx:requirements.update
+compile_pip_requirements(
+ name = "requirements",
+ src = "pyproject.toml",
+ requirements_txt = "requirements.txt",
+ target_compatible_with = _TARGET_COMPATIBLE_WITH,
+)
diff --git a/docs/sphinx/README.md b/docs/sphinx/README.md
new file mode 100644
index 0000000..98420e4
--- /dev/null
+++ b/docs/sphinx/README.md
@@ -0,0 +1,72 @@
+# rules_python Sphinx docs generation
+
+The docs for rules_python are generated using a combination of Sphinx, Bazel,
+and Readthedocs.org. The Markdown files in source control are unlikely to render
+properly without the Sphinx processing step because they rely on Sphinx and
+MyST-specific Markdown functionality.
+
+The actual sources that Sphinx consumes are in this directory, with Stardoc
+generating additional sources or Sphinx.
+
+Manually building the docs isn't necessary -- readthedocs.org will
+automatically build and deploy them when commits are pushed to the repo.
+
+## Generating docs for development
+
+Generating docs for development is a two-part process: starting a local HTTP
+server to serve the generated HTML, and re-generating the HTML when sources
+change. The quick start is:
+
+```
+bazel run //docs/sphinx:docs.serve # Run in separate terminal
+ibazel build //docs/sphinx:docs # Automatically rebuilds docs
+```
+
+This will build the docs and start a local webserver at http://localhost:8000
+where you can view the output. As you edit files, ibazel will detect the file
+changes and re-run the build process, and you can simply refresh your browser to
+see the changes. Using ibazel is not required; you can manually run the
+equivalent bazel command if desired.
+
+### Installing ibazel
+
+The `ibazel` tool can be used to automatically rebuild the docs as you
+development them. See the [ibazel docs](https://github.com/bazelbuild/bazel-watcher) for
+how to install it. The quick start for linux is:
+
+```
+sudo apt install npm
+sudo npm install -g @bazel/ibazel
+```
+
+## MyST Markdown flavor
+
+Sphinx is configured to parse Markdown files using MyST, which is a more
+advanced flavor of Markdown that supports most features of restructured text and
+integrates with Sphinx functionality such as automatic cross references,
+creating indexes, and using concise markup to generate rich documentation.
+
+MyST features and behaviors are controlled by the Sphinx configuration file,
+`docs/sphinx/conf.py`. For more info, see https://myst-parser.readthedocs.io.
+
+## Sphinx configuration
+
+The Sphinx-specific configuration files and input doc files live in
+docs/sphinx.
+
+The Sphinx configuration is `docs/sphinx/conf.py`. See
+https://www.sphinx-doc.org/ for details about the configuration file.
+
+## Readthedocs configuration
+
+There's two basic parts to the readthedocs configuration:
+
+* `.readthedocs.yaml`: This configuration file controls most settings, such as
+ the OS version used to build, Python version, dependencies, what Bazel
+ commands to run, etc.
+* https://readthedocs.org/projects/rules-python: This is the project
+ administration page. While most settings come from the config file, this
+ controls additional settings such as permissions, what versions are
+ published, when to publish changes, etc.
+
+For more readthedocs configuration details, see docs.readthedocs.io.
diff --git a/docs/sphinx/_includes/py_console_script_binary.md b/docs/sphinx/_includes/py_console_script_binary.md
new file mode 100644
index 0000000..7373c8a
--- /dev/null
+++ b/docs/sphinx/_includes/py_console_script_binary.md
@@ -0,0 +1,64 @@
+This rule is to make it easier to generate `console_script` entry points
+as per Python [specification].
+
+Generate a `py_binary` target for a particular console_script `entry_point`
+from a PyPI package, e.g. for creating an executable `pylint` target use:
+```starlark
+load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
+
+py_console_script_binary(
+ name = "pylint",
+ pkg = "@pip//pylint",
+)
+```
+
+Or for more advanced setups you can also specify extra dependencies and the
+exact script name you want to call. It is useful for tools like `flake8`, `pylint`,
+`pytest`, which have plugin discovery methods and discover dependencies from the
+PyPI packages available in the `PYTHONPATH`.
+```starlark
+load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
+
+py_console_script_binary(
+ name = "pylint_with_deps",
+ pkg = "@pip//pylint",
+ # Because `pylint` has multiple console_scripts available, we have to
+ # specify which we want if the name of the target name 'pylint_with_deps'
+ # cannot be used to guess the entry_point script.
+ script = "pylint",
+ deps = [
+ # One can add extra dependencies to the entry point.
+ # This specifically allows us to add plugins to pylint.
+ "@pip//pylint_print",
+ ],
+)
+```
+
+A specific Python version can be forced by using the generated version-aware
+wrappers, e.g. to force Python 3.9:
+```starlark
+load("@python_versions//3.9:defs.bzl", "py_console_script_binary")
+
+py_console_script_binary(
+ name = "yamllint",
+ pkg = "@pip//yamllint",
+)
+```
+
+Alternatively, the [`py_console_script_binary.binary_rule`] arg can be passed
+the version-bound `py_binary` symbol, or any other `py_binary`-compatible rule
+of your choosing:
+```starlark
+load("@python_versions//3.9:defs.bzl", "py_binary")
+load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
+
+py_console_script_binary(
+ name = "yamllint",
+ pkg = "@pip//yamllint:pkg",
+ binary_rule = py_binary,
+)
+```
+
+[specification]: https://packaging.python.org/en/latest/specifications/entry-points/
+[`py_console_script_binary.binary_rule`]: #py_console_script_binary_binary_rule
+
diff --git a/docs/sphinx/_stardoc_footer.md b/docs/sphinx/_stardoc_footer.md
new file mode 100644
index 0000000..7aa33f7
--- /dev/null
+++ b/docs/sphinx/_stardoc_footer.md
@@ -0,0 +1,15 @@
+
+[`Action`]: https://bazel.build/rules/lib/Action
+[`bool`]: https://bazel.build/rules/lib/bool
+[`depset`]: https://bazel.build/rules/lib/depset
+[`dict`]: https://bazel.build/rules/lib/dict
+[`File`]: https://bazel.build/rules/lib/File
+[`Label`]: https://bazel.build/rules/lib/Label
+[`list`]: https://bazel.build/rules/lib/list
+[`str`]: https://bazel.build/rules/lib/string
+[str]: https://bazel.build/rules/lib/string
+[`int`]: https://bazel.build/rules/lib/int
+[`struct`]: https://bazel.build/rules/lib/builtins/struct
+[`Target`]: https://bazel.build/rules/lib/Target
+[target-name]: https://bazel.build/concepts/labels#target-names
+[attr-label]: https://bazel.build/concepts/labels
diff --git a/docs/sphinx/_static/css/custom.css b/docs/sphinx/_static/css/custom.css
new file mode 100644
index 0000000..4b073d4
--- /dev/null
+++ b/docs/sphinx/_static/css/custom.css
@@ -0,0 +1,43 @@
+.wy-nav-content {
+ max-width: 70%;
+}
+
+.starlark-object {
+ border: thin solid grey;
+ margin-bottom: 1em;
+}
+
+.starlark-object h2 {
+ background-color: #e7f2fa;
+ border-bottom: thin solid grey;
+ padding-left: 0.5ex;
+}
+.starlark-object h3 {
+ background-color: #e7f2fa;
+ padding-left: 0.5ex;
+}
+
+.starlark-module-extension-tag-class h3 {
+ background-color: #add8e6;
+ padding-left: 0.5ex;
+}
+
+.starlark-object>p, .starlark-object>dl, .starlark-object>section>* {
+ /* Prevent the words from touching the border line */
+ padding-left: 0.5ex;
+}
+
+.starlark-signature {
+ font-family: monospace;
+}
+
+/* Fixup the headerlinks in param names */
+.starlark-object dt a {
+ /* Offset the link icon to be outside the colon */
+ position: relative;
+ right: -1ex;
+ /* Remove the empty space between the param name and colon */
+ width: 0;
+ /* Override the .headerlink margin */
+ margin-left: 0 !important;
+}
diff --git a/docs/sphinx/api/index.md b/docs/sphinx/api/index.md
new file mode 100644
index 0000000..028fab7
--- /dev/null
+++ b/docs/sphinx/api/index.md
@@ -0,0 +1,6 @@
+# API Reference
+
+```{toctree}
+:glob:
+**
+```
diff --git a/docs/sphinx/bazel_inventory.txt b/docs/sphinx/bazel_inventory.txt
new file mode 100644
index 0000000..869e66a
--- /dev/null
+++ b/docs/sphinx/bazel_inventory.txt
@@ -0,0 +1,17 @@
+# Sphinx inventory version 2
+# Project: Bazel
+# Version: 7.0.0
+# The remainder of this file is compressed using zlib
+Action bzl:obj 1 rules/lib/Action -
+File bzl:obj 1 rules/lib/File -
+Label bzl:obj 1 rules/lib/Label -
+Target bzl:obj 1 rules/lib/builtins/Target -
+bool bzl:obj 1 rules/lib/bool -
+depset bzl:obj 1 rules/lib/depset -
+dict bzl:obj 1 rules/lib/dict -
+label bzl:doc 1 concepts/labels -
+list bzl:obj: 1 rules/lib/list -
+python bzl:doc 1 reference/be/python -
+str bzl:obj 1 rules/lib/string -
+struct bzl:obj 1 rules/lib/builtins/struct -
+target-name bzl:doc 1 concepts/labels#target-names -
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py
new file mode 100644
index 0000000..e9af97a
--- /dev/null
+++ b/docs/sphinx/conf.py
@@ -0,0 +1,150 @@
+# Configuration file for the Sphinx documentation builder.
+
+import os
+
+# -- Project information
+project = "rules_python"
+copyright = "2023, The Bazel Authors"
+author = "Bazel"
+
+# NOTE: These are overriden by -D flags via --//sphinxdocs:extra_defines
+version = "0.0.0"
+release = version
+
+# -- General configuration
+# See https://www.sphinx-doc.org/en/master/usage/configuration.html
+# for more settings
+
+# Any extensions here not built into Sphinx must also be added to
+# the dependencies of //docs/sphinx:sphinx-builder
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.autosectionlabel",
+ "sphinx.ext.autosummary",
+ "sphinx.ext.doctest",
+ "sphinx.ext.duration",
+ "sphinx.ext.extlinks",
+ "sphinx.ext.intersphinx",
+ "myst_parser",
+ "sphinx_rtd_theme", # Necessary to get jquery to make flyout work
+]
+
+# Adapted from the template code:
+# https://github.com/readthedocs/readthedocs.org/blob/main/readthedocs/doc_builder/templates/doc_builder/conf.py.tmpl
+if os.environ.get("READTHEDOCS") == "True":
+ # Must come first because it can interfere with other extensions, according
+ # to the original conf.py template comments
+ extensions.insert(0, "readthedocs_ext.readthedocs")
+
+ if os.environ.get("READTHEDOCS_VERSION_TYPE") == "external":
+ # Insert after the main extension
+ extensions.insert(1, "readthedocs_ext.external_version_warning")
+ readthedocs_vcs_url = (
+ "http://github.com/bazelbuild/rules_python/pull/{}".format(
+ os.environ.get("READTHEDOCS_VERSION", "")
+ )
+ )
+ # The build id isn't directly available, but it appears to be encoded
+ # into the host name, so we can parse it from that. The format appears
+ # to be `build-X-project-Y-Z`, where:
+ # * X is an integer build id
+ # * Y is an integer project id
+ # * Z is the project name
+ _build_id = os.environ.get("HOSTNAME", "build-0-project-0-rules-python")
+ _build_id = _build_id.split("-")[1]
+ readthedocs_build_url = (
+ f"https://readthedocs.org/projects/rules-python/builds/{_build_id}"
+ )
+
+exclude_patterns = ["_includes/*"]
+templates_path = ["_templates"]
+primary_domain = None # The default is 'py', which we don't make much use of
+nitpicky = True
+
+# --- Intersphinx configuration
+
+intersphinx_mapping = {
+ "bazel": ("https://bazel.build/", "bazel_inventory.inv"),
+}
+
+# --- Extlinks configuration
+extlinks = {
+ "gh-path": (f"https://github.com/bazelbuild/rules_python/tree/main/%s", "%s"),
+}
+
+# --- MyST configuration
+# See https://myst-parser.readthedocs.io/en/latest/configuration.html
+# for more settings
+
+# See https://myst-parser.readthedocs.io/en/latest/syntax/optional.html
+# for additional extensions.
+myst_enable_extensions = [
+ "fieldlist",
+ "attrs_block",
+ "attrs_inline",
+ "colon_fence",
+ "deflist",
+ "substitution",
+]
+
+myst_substitutions = {}
+
+# -- Options for HTML output
+# See https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+# For additional html settings
+
+# See https://sphinx-rtd-theme.readthedocs.io/en/stable/configuring.html for
+# them-specific options
+html_theme = "sphinx_rtd_theme"
+html_theme_options = {}
+
+# The html_context settings are part of the jinja context used by the themes.
+html_context = {
+ # This controls whether the flyout menu is shown. It is always false
+ # because:
+ # * For local builds, the flyout menu is empty and doesn't show in the
+ # same place as for RTD builds. No point in showing it locally.
+ # * For RTD builds, the flyout menu is always automatically injected,
+ # so having it be True makes the flyout show up twice.
+ "READTHEDOCS": False,
+ "PRODUCTION_DOMAIN": "readthedocs.org",
+ # This is the path to a page's source (after the github user/repo/commit)
+ "conf_py_path": "/docs/sphinx/",
+ "github_user": "bazelbuild",
+ "github_repo": "rules_python",
+ # The git version that was checked out, e.g. the tag or branch name
+ "github_version": os.environ.get("READTHEDOCS_GIT_IDENTIFIER", ""),
+ # For local builds, the github link won't work. Disabling it replaces
+ # it with a "view source" link to view the source Sphinx saw, which
+ # is useful for local development.
+ "display_github": os.environ.get("READTHEDOCS") == "True",
+ "commit": os.environ.get("READTHEDOCS_GIT_COMMIT_HASH", "unknown commit"),
+ # Used by readthedocs_ext.external_version_warning extension
+ # This is the PR number being built
+ "current_version": os.environ.get("READTHEDOCS_VERSION", ""),
+}
+
+# Keep this in sync with the stardoc templates
+html_permalinks_icon = "¶"
+
+# These folders are copied to the documentation's HTML output
+html_static_path = ["_static"]
+
+# These paths are either relative to html_static_path
+# or fully qualified paths (eg. https://...)
+html_css_files = [
+ "css/custom.css",
+]
+
+# -- Options for EPUB output
+epub_show_urls = "footnote"
+
+suppress_warnings = []
+
+
+def setup(app):
+ # Pygments says it supports starlark, but it doesn't seem to actually
+ # recognize `starlark` as a name. So just manually map it to python.
+ from sphinx.highlighting import lexer_classes
+
+ app.add_lexer("starlark", lexer_classes["python"])
diff --git a/docs/coverage.md b/docs/sphinx/coverage.md
index 63f2578..3e0e673 100644
--- a/docs/coverage.md
+++ b/docs/sphinx/coverage.md
@@ -28,12 +28,14 @@ python_register_toolchains(
)
```
-NOTE: This will implicitly add the version of `coverage` bundled with
+:::{note}
+This will implicitly add the version of `coverage` bundled with
`rules_python` to the dependencies of `py_test` rules when `bazel coverage` is
run. If a target already transitively depends on a different version of
`coverage`, then behavior is undefined -- it is undefined which version comes
first in the import path. If you find yourself in this situation, then you'll
need to manually configure coverage (see below).
+:::
## Manually configuring coverage
diff --git a/docs/sphinx/gazelle.md b/docs/sphinx/gazelle.md
new file mode 100644
index 0000000..89f26d6
--- /dev/null
+++ b/docs/sphinx/gazelle.md
@@ -0,0 +1,9 @@
+# Gazelle plugin
+
+[Gazelle](https://github.com/bazelbuild/bazel-gazelle)
+is a build file generator for Bazel projects. It can create new `BUILD.bazel` files for a project that follows language conventions and update existing build files to include new sources, dependencies, and options.
+
+Bazel may run Gazelle using the Gazelle rule, or it may be installed and run as a command line tool.
+
+See the documentation for Gazelle with rules_python in the {gh-path}`gazelle`
+directory.
diff --git a/docs/sphinx/getting-started.md b/docs/sphinx/getting-started.md
new file mode 100644
index 0000000..d7542fa
--- /dev/null
+++ b/docs/sphinx/getting-started.md
@@ -0,0 +1,181 @@
+# Getting started
+
+The following two sections cover using `rules_python` with bzlmod and
+the older way of configuring bazel with a `WORKSPACE` file.
+
+
+## Using bzlmod
+
+**IMPORTANT: bzlmod support is still in Beta; APIs are subject to change.**
+
+The first step to using rules_python with bzlmod is to add the dependency to
+your MODULE.bazel file:
+
+```starlark
+# Update the version "0.0.0" to the release found here:
+# https://github.com/bazelbuild/rules_python/releases.
+bazel_dep(name = "rules_python", version = "0.0.0")
+```
+
+Once added, you can load the rules and use them:
+
+```starlark
+load("@rules_python//python:py_binary.bzl", "py_binary")
+
+py_binary(...)
+```
+
+Depending on what you're doing, you likely want to do some additional
+configuration to control what Python version is used; read the following
+sections for how to do that.
+
+### Toolchain registration with bzlmod
+
+A default toolchain is automatically configured depending on
+`rules_python`. Note, however, the version used tracks the most recent Python
+release and will change often.
+
+If you want to use a specific Python version for your programs, then how
+to do so depends on if you're configuring the root module or not. The root
+module is special because it can set the *default* Python version, which
+is used by the version-unaware rules (e.g. `//python:py_binary.bzl` et al). For
+submodules, it's recommended to use the version-aware rules to pin your programs
+to a specific Python version so they don't accidentally run with a different
+version configured by the root module.
+
+#### Configuring and using the default Python version
+
+To specify what the default Python version is, set `is_default = True` when
+calling `python.toolchain()`. This can only be done by the root module; it is
+silently ignored if a submodule does it. Similarly, using the version-unaware
+rules (which always use the default Python version) should only be done by the
+root module. If submodules use them, then they may run with a different Python
+version than they expect.
+
+```starlark
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+
+python.toolchain(
+ python_version = "3.11",
+ is_default = True,
+)
+```
+
+Then use the base rules from e.g. `//python:py_binary.bzl`.
+
+#### Pinning to a Python version
+
+Pinning to a version allows targets to force that a specific Python version is
+used, even if the root module configures a different version as a default. This
+is most useful for two cases:
+
+1. For submodules to ensure they run with the appropriate Python version
+2. To allow incremental, per-target, upgrading to newer Python versions,
+ typically in a mono-repo situation.
+
+To configure a submodule with the version-aware rules, request the particular
+version you need, then use the `@python_versions` repo to use the rules that
+force specific versions:
+
+```starlark
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+
+python.toolchain(
+ python_version = "3.11",
+)
+use_repo(python, "python_versions")
+```
+
+Then use e.g. `load("@python_versions//3.11:defs.bzl", "py_binary")` to use
+the rules that force that particular version. Multiple versions can be specified
+and use within a single build.
+
+For more documentation, see the bzlmod examples under the {gh-path}`examples`
+folder. Look for the examples that contain a `MODULE.bazel` file.
+
+#### Other toolchain details
+
+The `python.toolchain()` call makes its contents available under a repo named
+`python_X_Y`, where X and Y are the major and minor versions. For example,
+`python.toolchain(python_version="3.11")` creates the repo `@python_3_11`.
+Remember to call `use_repo()` to make repos visible to your module:
+`use_repo(python, "python_3_11")`
+
+## Using a WORKSPACE file
+
+To import rules_python in your project, you first need to add it to your
+`WORKSPACE` file, using the snippet provided in the
+[release you choose](https://github.com/bazelbuild/rules_python/releases)
+
+To depend on a particular unreleased version, you can do the following:
+
+```starlark
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+
+# Update the SHA and VERSION to the lastest version available here:
+# https://github.com/bazelbuild/rules_python/releases.
+
+SHA="84aec9e21cc56fbc7f1335035a71c850d1b9b5cc6ff497306f84cced9a769841"
+
+VERSION="0.23.1"
+
+http_archive(
+ name = "rules_python",
+ sha256 = SHA,
+ strip_prefix = "rules_python-{}".format(VERSION),
+ url = "https://github.com/bazelbuild/rules_python/releases/download/{}/rules_python-{}.tar.gz".format(VERSION,VERSION),
+)
+
+load("@rules_python//python:repositories.bzl", "py_repositories")
+
+py_repositories()
+```
+
+### Toolchain registration
+
+To register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `WORKSPACE` file:
+
+```starlark
+load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+
+python_register_toolchains(
+ name = "python_3_11",
+ # Available versions are listed in @rules_python//python:versions.bzl.
+ # We recommend using the same version your team is already standardized on.
+ python_version = "3.11",
+)
+
+load("@python_3_11//:defs.bzl", "interpreter")
+
+load("@rules_python//python:pip.bzl", "pip_parse")
+
+pip_parse(
+ ...
+ python_interpreter_target = interpreter,
+ ...
+)
+```
+
+After registration, your Python targets will use the toolchain's interpreter during execution, but a system-installed interpreter
+is still used to 'bootstrap' Python targets (see https://github.com/bazelbuild/rules_python/issues/691).
+You may also find some quirks while using this toolchain. Please refer to [python-build-standalone documentation's _Quirks_ section](https://python-build-standalone.readthedocs.io/en/latest/quirks.html).
+
+## Toolchain usage in other rules
+
+Python toolchains can be utilized in other bazel rules, such as `genrule()`, by adding the `toolchains=["@rules_python//python:current_py_toolchain"]` attribute. You can obtain the path to the Python interpreter using the `$(PYTHON2)` and `$(PYTHON3)` ["Make" Variables](https://bazel.build/reference/be/make-variables). See the
+{gh-path}`test_current_py_toolchain <tests/load_from_macro/BUILD.bazel>` target for an example.
+
+## "Hello World"
+
+Once you've imported the rule set into your `WORKSPACE` using any of these
+methods, you can then load the core rules in your `BUILD` files with the following:
+
+```starlark
+load("@rules_python//python:defs.bzl", "py_binary")
+
+py_binary(
+ name = "main",
+ srcs = ["main.py"],
+)
+```
diff --git a/docs/sphinx/glossary.md b/docs/sphinx/glossary.md
new file mode 100644
index 0000000..f54034d
--- /dev/null
+++ b/docs/sphinx/glossary.md
@@ -0,0 +1,28 @@
+# Glossary
+
+{.glossary}
+
+common attributes
+: Every rule has a set of common attributes. See Bazel's
+ [Common attributes](https://bazel.build/reference/be/common-definitions#common-attributes)
+ for a complete listing
+
+rule callable
+: A function that behaves like a rule. This includes, but is not is not
+ limited to:
+ * Accepts a `name` arg and other {term}`common attributes`.
+ * Has no return value (i.e. returns `None`).
+ * Creates at least a target named `name`
+
+ There is usually an implicit interface about what attributes and values are
+ accepted; refer to the respective API accepting this type.
+
+simple label
+: A `str` or `Label` object but not a _direct_ `select` object. These usually
+ mean a string manipulation is occuring, which can't be done on `select`
+ objects. Such attributes are usually still configurable if an alias is used,
+ and a reference to the alias is passed instead.
+
+nonconfigurable
+: A nonconfigurable value cannot use `select`. See Bazel's
+ [configurable attributes](https://bazel.build/reference/be/common-definitions#configurable-attributes) documentation.
diff --git a/docs/sphinx/index.md b/docs/sphinx/index.md
new file mode 100644
index 0000000..0a9c70f
--- /dev/null
+++ b/docs/sphinx/index.md
@@ -0,0 +1,69 @@
+# Python Rules for Bazel
+
+rules_python is the home of the core Python rules -- `py_library`,
+`py_binary`, `py_test`, `py_proto_library`, and related symbols that provide the basis for Python
+support in Bazel. It also contains package installation rules for integrating with PyPI and other indices.
+
+Documentation for rules_python lives here and in the
+[Bazel Build Encyclopedia](https://docs.bazel.build/versions/master/be/python.html).
+
+Examples are in the {gh-path}`examples` directory.
+
+Currently, the core rules build into the Bazel binary, and the symbols in this
+repository are simple aliases. However, we are migrating the rules to Starlark and removing them from the Bazel binary. Therefore, the future-proof way to depend on Python rules is via this repository. See
+{ref}`Migrating from the Bundled Rules` below.
+
+The core rules are stable. Their implementation in Bazel is subject to Bazel's
+[backward compatibility policy](https://docs.bazel.build/versions/master/backward-compatibility.html).
+Once migrated to rules_python, they may evolve at a different
+rate, but this repository will still follow [semantic versioning](https://semver.org).
+
+The Bazel community maintains this repository. Neither Google nor the Bazel team provides support for the code. However, this repository is part of the test suite used to vet new Bazel releases. See
+{gh-path}`How to contribute <CONTRIBUTING.md>` for information on our development workflow.
+
+## Bzlmod support
+
+- Status: Beta
+- Full Feature Parity: No
+
+See {gh-path}`Bzlmod support <BZLMOD_SUPPORT.md>` for more details
+
+## Migrating from the bundled rules
+
+The core rules are currently available in Bazel as built-in symbols, but this
+form is deprecated. Instead, you should depend on rules_python in your
+`WORKSPACE` file and load the Python rules from
+`@rules_python//python:defs.bzl`.
+
+A [buildifier](https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md)
+fix is available to automatically migrate `BUILD` and `.bzl` files to add the
+appropriate `load()` statements and rewrite uses of `native.py_*`.
+
+```sh
+# Also consider using the -r flag to modify an entire workspace.
+buildifier --lint=fix --warnings=native-py <files>
+```
+
+Currently, the `WORKSPACE` file needs to be updated manually as per [Getting
+started](getting-started).
+
+Note that Starlark-defined bundled symbols underneath
+`@bazel_tools//tools/python` are also deprecated. These are not yet rewritten
+by buildifier.
+
+
+```{toctree}
+:hidden:
+self
+getting-started
+pypi-dependencies
+pip
+coverage
+gazelle
+Contributing <contributing>
+support
+Changelog <changelog>
+api/index
+glossary
+genindex
+```
diff --git a/docs/sphinx/pip.md b/docs/sphinx/pip.md
new file mode 100644
index 0000000..34248d2
--- /dev/null
+++ b/docs/sphinx/pip.md
@@ -0,0 +1,84 @@
+(pip-integration)=
+# Pip Integration
+
+To pull in dependencies from PyPI, the `pip_parse` function is used, which
+invokes `pip` to download and install dependencies from PyPI.
+
+In your WORKSPACE file:
+
+```starlark
+load("@rules_python//python:pip.bzl", "pip_parse")
+
+pip_parse(
+ name = "pip_deps",
+ requirements_lock = ":requirements.txt",
+)
+
+load("@pip_deps//:requirements.bzl", "install_deps")
+
+install_deps()
+```
+
+You can then reference installed dependencies from a `BUILD` file with:
+
+```starlark
+load("@pip_deps//:requirements.bzl", "requirement")
+
+py_library(
+ name = "bar",
+ ...
+ deps = [
+ "//my/other:dep",
+ requirement("requests"),
+ requirement("numpy"),
+ ],
+)
+```
+
+In addition to the `requirement` macro, which is used to access the generated `py_library`
+target generated from a package's wheel, The generated `requirements.bzl` file contains
+functionality for exposing [entry points][whl_ep] as `py_binary` targets as well.
+
+[whl_ep]: https://packaging.python.org/specifications/entry-points/
+
+```starlark
+load("@pip_deps//:requirements.bzl", "entry_point")
+
+alias(
+ name = "pip-compile",
+ actual = entry_point(
+ pkg = "pip-tools",
+ script = "pip-compile",
+ ),
+)
+```
+
+Note that for packages whose name and script are the same, only the name of the package
+is needed when calling the `entry_point` macro.
+
+```starlark
+load("@pip_deps//:requirements.bzl", "entry_point")
+
+alias(
+ name = "flake8",
+ actual = entry_point("flake8"),
+)
+```
+
+(vendoring-requirements)=
+## Vendoring the requirements.bzl file
+
+In some cases you may not want to generate the requirements.bzl file as a repository rule
+while Bazel is fetching dependencies. For example, if you produce a reusable Bazel module
+such as a ruleset, you may want to include the requirements.bzl file rather than make your users
+install the WORKSPACE setup to generate it.
+See https://github.com/bazelbuild/rules_python/issues/608
+
+This is the same workflow as Gazelle, which creates `go_repository` rules with
+[`update-repos`](https://github.com/bazelbuild/bazel-gazelle#update-repos)
+
+To do this, use the "write to source file" pattern documented in
+https://blog.aspect.dev/bazel-can-write-to-the-source-folder
+to put a copy of the generated requirements.bzl into your project.
+Then load the requirements.bzl file directly rather than from the generated repository.
+See the example in rules_python/examples/pip_parse_vendored.
diff --git a/docs/sphinx/pypi-dependencies.md b/docs/sphinx/pypi-dependencies.md
new file mode 100644
index 0000000..880945f
--- /dev/null
+++ b/docs/sphinx/pypi-dependencies.md
@@ -0,0 +1,217 @@
+# Using dependencies from PyPI
+
+Using PyPI packages (aka "pip install") involves two main steps.
+
+1. [Installing third party packages](#installing-third-party-packages)
+2. [Using third party packages as dependencies](#using-third-party-packages)
+
+{#installing-third-party-packages}
+## Installing third party packages
+
+### Using bzlmod
+
+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. Include in the `MODULE.bazel` the toolchain extension as shown
+in the first bzlmod example above.
+
+```starlark
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+pip.parse(
+ hub_name = "my_deps",
+ python_version = "3.11",
+ requirements_lock = "//:requirements_lock_3_11.txt",
+)
+use_repo(pip, "my_deps")
+```
+For more documentation, including how the rules can update/create a requirements
+file, see the bzlmod examples under the {gh-path}`examples` folder.
+
+### Using a WORKSPACE file
+
+To add pip dependencies to your `WORKSPACE`, load the `pip_parse` function and
+call it to create the central external repo and individual wheel external repos.
+
+```starlark
+load("@rules_python//python:pip.bzl", "pip_parse")
+
+# Create a central repo that knows about the dependencies needed from
+# requirements_lock.txt.
+pip_parse(
+ name = "my_deps",
+ requirements_lock = "//path/to:requirements_lock.txt",
+)
+# Load the starlark macro, which will define your dependencies.
+load("@my_deps//:requirements.bzl", "install_deps")
+# Call it to define repos for your requirements.
+install_deps()
+```
+
+### pip rules
+
+Note that since `pip_parse` is a repository rule and therefore executes pip at
+WORKSPACE-evaluation time, Bazel has no information about the Python toolchain
+and cannot enforce that the interpreter used to invoke pip matches the
+interpreter used to run `py_binary` targets. By default, `pip_parse` uses the
+system command `"python3"`. To override this, pass in the `python_interpreter`
+attribute or `python_interpreter_target` attribute to `pip_parse`.
+
+You can have multiple `pip_parse`s in the same workspace. Or use the pip
+extension multiple times when using bzlmod. This configuration will create
+multiple external repos that have no relation to one another and may result in
+downloading the same wheels numerous times.
+
+As with any repository rule, if you would like to ensure that `pip_parse` is
+re-executed to pick up a non-hermetic change to your environment (e.g., updating
+your system `python` interpreter), you can force it to re-execute by running
+`bazel sync --only [pip_parse name]`.
+
+{#using-third-party-packages}
+## Using third party packages as dependencies
+
+Each extracted wheel repo contains a `py_library` target representing
+the wheel's contents. There are two ways to access this library. The
+first uses the `requirement()` function defined in the central
+repo's `//:requirements.bzl` file. This function maps a pip package
+name to a label:
+
+```starlark
+load("@my_deps//:requirements.bzl", "requirement")
+
+py_library(
+ name = "mylib",
+ srcs = ["mylib.py"],
+ deps = [
+ ":myotherlib",
+ requirement("some_pip_dep"),
+ requirement("another_pip_dep"),
+ ]
+)
+```
+
+The reason `requirement()` exists is to insulate from
+changes to the underlying repository and label strings. However, those
+labels have become directly used, so aren't able to easily change regardless.
+
+On the other hand, using `requirement()` has several drawbacks; see
+[this issue][requirements-drawbacks] for an enumeration. If you don't
+want to use `requirement()`, you can use the library
+labels directly instead. For `pip_parse`, the labels are of the following form:
+
+```starlark
+@{name}_{package}//:pkg
+```
+
+Here `name` is the `name` attribute that was passed to `pip_parse` and
+`package` is the pip package name with characters that are illegal in
+Bazel label names (e.g. `-`, `.`) replaced with `_`. If you need to
+update `name` from "old" to "new", then you can run the following
+buildozer command:
+
+```shell
+buildozer 'substitute deps @old_([^/]+)//:pkg @new_${1}//:pkg' //...:*
+```
+
+[requirements-drawbacks]: https://github.com/bazelbuild/rules_python/issues/414
+
+### 'Extras' dependencies
+
+Any 'extras' specified in the requirements lock file will be automatically added
+as transitive dependencies of the package. In the example above, you'd just put
+`requirement("useful_dep")`.
+
+### Packaging cycles
+
+Sometimes PyPi packages contain dependency cycles -- for instance `sphinx`
+depends on `sphinxcontrib-serializinghtml`. When using them as `requirement()`s,
+ala
+
+```
+py_binary(
+ name = "doctool",
+ ...
+ deps = [
+ requirement("sphinx"),
+ ]
+)
+```
+
+Bazel will protest because it doesn't support cycles in the build graph --
+
+```
+ERROR: .../external/pypi_sphinxcontrib_serializinghtml/BUILD.bazel:44:6: in alias rule @pypi_sphinxcontrib_serializinghtml//:pkg: cycle in dependency graph:
+ //:doctool (...)
+ @pypi//sphinxcontrib_serializinghtml:pkg (...)
+.-> @pypi_sphinxcontrib_serializinghtml//:pkg (...)
+| @pypi_sphinxcontrib_serializinghtml//:_pkg (...)
+| @pypi_sphinx//:pkg (...)
+| @pypi_sphinx//:_pkg (...)
+`-- @pypi_sphinxcontrib_serializinghtml//:pkg (...)
+```
+
+The `experimental_requirement_cycles` argument allows you to work around these
+issues by specifying groups of packages which form cycles. `pip_parse` will
+transparently fix the cycles for you and provide the cyclic dependencies
+simultaneously.
+
+```
+pip_parse(
+ ...
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-serializinghtml",
+ ]
+ },
+)
+```
+
+`pip_parse` supports fixing multiple cycles simultaneously, however cycles must
+be distinct. `apache-airflow` for instance has dependency cycles with a number
+of its optional dependencies, which means those optional dependencies must all
+be a part of the `airflow` cycle. For instance --
+
+```
+pip_parse(
+ ...
+ experimental_requirement_cycles = {
+ "airflow": [
+ "apache-airflow",
+ "apache-airflow-providers-common-sql",
+ "apache-airflow-providers-postgres",
+ "apache-airflow-providers-sqlite",
+ ]
+ }
+)
+```
+
+Alternatively, one could resolve the cycle by removing one leg of it.
+
+For example while `apache-airflow-providers-sqlite` is "baked into" the Airflow
+package, `apache-airflow-providers-postgres` is not and is an optional feature.
+Rather than listing `apache-airflow[postgres]` in your `requirements.txt` which
+would expose a cycle via the extra, one could either _manually_ depend on
+`apache-airflow` and `apache-airflow-providers-postgres` separately as
+requirements. Bazel rules which need only `apache-airflow` can take it as a
+dependency, and rules which explicitly want to mix in
+`apache-airflow-providers-postgres` now can.
+
+Alternatively, one could use `rules_python`'s patching features to remove one
+leg of the dependency manually. For instance by making
+`apache-airflow-providers-postgres` not explicitly depend on `apache-airflow` or
+perhaps `apache-airflow-providers-common-sql`.
+
+## Consuming Wheel Dists Directly
+
+If you need to depend on the wheel dists themselves, for instance, to pass them
+to some other packaging tool, you can get a handle to them with the
+`whl_requirement` macro. For example:
+
+```starlark
+filegroup(
+ name = "whl_files",
+ data = [
+ whl_requirement("boto3"),
+ ]
+)
+```
diff --git a/docs/sphinx/pyproject.toml b/docs/sphinx/pyproject.toml
new file mode 100644
index 0000000..d36c9f2
--- /dev/null
+++ b/docs/sphinx/pyproject.toml
@@ -0,0 +1,13 @@
+[project]
+name = "rules_python_docs"
+version = "0.0.0"
+
+dependencies = [
+ # NOTE: This is only used as input to create the resolved requirements.txt
+ # file, which is what builds, both Bazel and Readthedocs, both use.
+ "sphinx",
+ "myst-parser",
+ "sphinx_rtd_theme",
+ "readthedocs-sphinx-ext",
+ "absl-py",
+]
diff --git a/docs/sphinx/readthedocs_build.sh b/docs/sphinx/readthedocs_build.sh
new file mode 100755
index 0000000..c611b7c
--- /dev/null
+++ b/docs/sphinx/readthedocs_build.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -eou pipefail
+
+declare -a extra_env
+while IFS='=' read -r -d '' name value; do
+ if [[ "$name" == READTHEDOCS* ]]; then
+ extra_env+=("--//sphinxdocs:extra_env=$name=$value")
+ fi
+done < <(env -0)
+
+# In order to get the build number, we extract it from the host name
+extra_env+=("--//sphinxdocs:extra_env=HOSTNAME=$HOSTNAME")
+
+set -x
+bazel run \
+ --config=rtd \
+ "--//sphinxdocs:extra_defines=version=$READTHEDOCS_VERSION" \
+ "${extra_env[@]}" \
+ //docs/sphinx:readthedocs_install
diff --git a/docs/sphinx/requirements.txt b/docs/sphinx/requirements.txt
new file mode 100644
index 0000000..85c61f3
--- /dev/null
+++ b/docs/sphinx/requirements.txt
@@ -0,0 +1,341 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+# bazel run //docs/sphinx:requirements.update
+#
+absl-py==2.0.0 \
+ --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3 \
+ --hash=sha256:d9690211c5fcfefcdd1a45470ac2b5c5acd45241c3af71eed96bc5441746c0d5
+ # via rules-python-docs (docs/sphinx/pyproject.toml)
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
+certifi==2023.11.17 \
+ --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
+ --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
+ # via requests
+charset-normalizer==3.3.2 \
+ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
+ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
+ --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
+ --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
+ --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
+ --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
+ --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
+ --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
+ --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
+ --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
+ --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
+ --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
+ --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
+ --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
+ --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
+ --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
+ --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
+ --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
+ --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
+ --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
+ --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
+ --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
+ --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
+ --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
+ --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
+ --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
+ --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
+ --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
+ --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
+ --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
+ --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
+ --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
+ --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
+ --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
+ --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
+ --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
+ --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
+ --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
+ --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
+ --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
+ --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
+ --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
+ --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
+ --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
+ --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
+ --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
+ --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
+ --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
+ --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
+ --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
+ --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
+ --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
+ --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
+ --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
+ --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
+ --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
+ --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
+ --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
+ --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
+ --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
+ --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
+ --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
+ --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
+ --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
+ --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
+ --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
+ --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
+ --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
+ --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
+ --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
+ --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
+ --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
+ --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
+ --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
+ --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
+ --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
+ --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
+ --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
+ --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
+ --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
+ --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
+ --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
+ --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
+ --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
+ --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
+ --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
+ --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
+ --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
+ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
+ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
+ # via requests
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via
+ # myst-parser
+ # sphinx
+ # sphinx-rtd-theme
+idna==3.6 \
+ --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
+ --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
+ # via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via
+ # myst-parser
+ # readthedocs-sphinx-ext
+ # sphinx
+markdown-it-py==3.0.0 \
+ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
+ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
+ # via
+ # mdit-py-plugins
+ # myst-parser
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
+mdit-py-plugins==0.4.0 \
+ --hash=sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9 \
+ --hash=sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b
+ # via myst-parser
+mdurl==0.1.2 \
+ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
+ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
+ # via markdown-it-py
+myst-parser==2.0.0 \
+ --hash=sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14 \
+ --hash=sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead
+ # via rules-python-docs (docs/sphinx/pyproject.toml)
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via
+ # readthedocs-sphinx-ext
+ # sphinx
+pygments==2.17.2 \
+ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
+ --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
+ # via sphinx
+pyyaml==6.0.1 \
+ --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
+ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
+ --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
+ --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
+ --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
+ --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
+ --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
+ --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
+ --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
+ --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
+ --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
+ --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
+ --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
+ --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
+ --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
+ --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
+ --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
+ --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
+ --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
+ --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
+ --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
+ --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
+ --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
+ --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
+ --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
+ --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
+ --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
+ --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
+ --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
+ --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
+ --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
+ --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
+ --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
+ --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
+ --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
+ --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
+ --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
+ --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
+ --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
+ --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
+ --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
+ --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
+ --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
+ --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
+ --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
+ --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
+ --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
+ --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
+ --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
+ --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
+ # via myst-parser
+readthedocs-sphinx-ext==2.2.3 \
+ --hash=sha256:6583c26791a5853ee9e57ce9db864e2fb06808ba470f805d74d53fc50811e012 \
+ --hash=sha256:e9d911792789b88ae12e2be94d88c619f89a4fa1fe9e42c1505c9930a07163d8
+ # via rules-python-docs (docs/sphinx/pyproject.toml)
+requests==2.31.0 \
+ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
+ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+ # via
+ # readthedocs-sphinx-ext
+ # sphinx
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # myst-parser
+ # rules-python-docs (docs/sphinx/pyproject.toml)
+ # sphinx-rtd-theme
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-jquery
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinx-rtd-theme==2.0.0 \
+ --hash=sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b \
+ --hash=sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586
+ # via rules-python-docs (docs/sphinx/pyproject.toml)
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jquery==4.1 \
+ --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \
+ --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae
+ # via sphinx-rtd-theme
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via sphinx
+urllib3==2.1.0 \
+ --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
+ --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
+ # via requests
diff --git a/docs/sphinx/support.md b/docs/sphinx/support.md
new file mode 100644
index 0000000..a2b8e3a
--- /dev/null
+++ b/docs/sphinx/support.md
@@ -0,0 +1,61 @@
+# Support Policy
+
+The Bazel community maintains this repository. Neither Google nor the Bazel team
+provides support for the code. However, this repository is part of the test
+suite used to vet new Bazel releases. See the <project:#contributing>
+page for information on our development workflow.
+
+## Supported rules_python Versions
+
+In general, only the latest version is supported. Backporting changes is
+done on a best effort basis based on severity, risk of regressions, and
+the willingness of volunteers.
+
+If you want or need particular functionality backported, then the best way
+is to open a PR to demonstrate the feasibility of the backport.
+
+## Supported Bazel Versions
+
+The supported Bazel versions are:
+
+1. The latest rolling release
+2. The active major release.
+3. The major release prior to the active release.
+
+For (2) and (3) above, only the latest minor/patch version of the major release
+is officially supported. Earlier minor/patch versions are supported on a
+best-effort basis only. We increase the minimum minor/patch version as necessary
+to fix bugs or introduce functionality relying on features introduced in later
+minor/patch versions.
+
+See [Bazel's release support matrix](https://bazel.build/release#support-matrix)
+for what versions are the rolling, active, and prior releases.
+
+## Supported Platforms
+
+We only support the platforms that our continuous integration jobs run, which
+is Linux, Mac, and Windows. Code to support other platforms is allowed, but
+can only be on a best-effort basis.
+
+## Compatibility Policy
+
+We generally follow the [Bazel Rule
+Compatibility](https://bazel.build/release/rule-compatibility) guidelines, which
+provides a path from an arbitrary release to the latest release in an
+incremental fashion.
+
+Breaking changes are allowed, but follow a process to introduce them over
+a series of releases to so users can still incrementally upgrade. See the
+[Breaking Changes](contributing#breaking-changes) doc for the process.
+
+## Experimental Features
+
+An experimental features is functionality that may not be ready for general
+use and may change quickly and/or significantly. Such features are denoted in
+their name or API docs as "experimental". They may have breaking changes made at
+any time.
+
+If you like or use an experimental feature, then file issues to request it be
+taken out of experimental. Often times these features are experimental because
+we need feedback or experience to verify they are working, useful, and worth the
+effort of supporting.
diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel
index feb1cfb..f6372ea 100644
--- a/examples/BUILD.bazel
+++ b/examples/BUILD.bazel
@@ -11,62 +11,5 @@
# 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.
-load("//tools/bazel_integration_test:bazel_integration_test.bzl", "bazel_integration_test")
-
-package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
-
-bazel_integration_test(
- name = "build_file_generation_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "bzlmod_build_file_generation_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "pip_install_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "pip_parse_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "pip_parse_vendored_example",
- timeout = "long",
- tags = ["fix-windows"],
-)
-
-bazel_integration_test(
- name = "pip_repository_annotations_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "py_proto_library_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "py_proto_library_example_bzlmod",
- timeout = "long",
- bzlmod = True,
- dirname = "py_proto_library",
-)
-
-bazel_integration_test(
- name = "multi_python_versions_example",
- timeout = "long",
-)
-
-bazel_integration_test(
- name = "bzlmod_example",
- bzlmod = True,
- override_bazel_version = "6.0.0",
-)
diff --git a/examples/build_file_generation/.bazelrc b/examples/build_file_generation/.bazelrc
index 28f634b..7e6911f 100644
--- a/examples/build_file_generation/.bazelrc
+++ b/examples/build_file_generation/.bazelrc
@@ -3,3 +3,7 @@ test --test_output=errors --enable_runfiles
# Windows requires these for multi-python support:
build --enable_runfiles
startup --windows_enable_symlinks
+
+# The bzlmod version of this example is in examples/bzlmod_build_file_generation
+# Once WORKSPACE support is dropped, this example can be entirely deleted.
+build --experimental_enable_bzlmod=false
diff --git a/examples/build_file_generation/BUILD.bazel b/examples/build_file_generation/BUILD.bazel
index 928fb12..4d270dd 100644
--- a/examples/build_file_generation/BUILD.bazel
+++ b/examples/build_file_generation/BUILD.bazel
@@ -6,14 +6,12 @@ load("@bazel_gazelle//:def.bzl", "gazelle")
load("@pip//:requirements.bzl", "all_whl_requirements")
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")
compile_pip_requirements(
name = "requirements",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock.txt",
requirements_windows = "requirements_windows.txt",
)
@@ -45,9 +43,6 @@ gazelle_python_manifest(
# NOTE: We can pass a list just like in `bzlmod_build_file_generation` example
# but we keep a single target here for regression testing.
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.
@@ -57,7 +52,6 @@ gazelle_python_manifest(
# See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example
gazelle(
name = "gazelle",
- data = GAZELLE_PYTHON_RUNTIME_DEPS,
gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary",
)
@@ -71,6 +65,7 @@ py_library(
deps = [
"//random_number_generator",
"@pip//flask",
+ "@pip//sphinx",
],
)
diff --git a/examples/build_file_generation/WORKSPACE b/examples/build_file_generation/WORKSPACE
index 7c74835..e283260 100644
--- a/examples/build_file_generation/WORKSPACE
+++ b/examples/build_file_generation/WORKSPACE
@@ -20,21 +20,20 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
- sha256 = "6dc2da7ab4cf5d7bfc7c949776b1b7c733f05e56edc4bcd9022bb249d2e2a996",
+ sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.39.1/rules_go-v0.39.1.zip",
- "https://github.com/bazelbuild/rules_go/releases/download/v0.39.1/rules_go-v0.39.1.zip",
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
+ "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
],
)
# Download the bazel_gazelle ruleset.
-
http_archive(
name = "bazel_gazelle",
- sha256 = "727f3e4edd96ea20c29e8c2ca9e8d2af724d8c7778e7923a854b2c80952bc405",
+ sha256 = "d3fa66a39028e97d76f9e2db8f1b0c11c099e8e01bf363a923074784e451f809",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.30.0/bazel-gazelle-v0.30.0.tar.gz",
- "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.30.0/bazel-gazelle-v0.30.0.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.33.0/bazel-gazelle-v0.33.0.tar.gz",
+ "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.33.0/bazel-gazelle-v0.33.0.tar.gz",
],
)
@@ -71,8 +70,11 @@ local_repository(
path = "../../gazelle",
)
-# Next we load the toolchain from rules_python.
-load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+# Next we load the setup and toolchain from rules_python.
+load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
+
+# Perform general setup
+py_repositories()
# We now register a hermetic Python interpreter rather than relying on a system-installed interpreter.
# This toolchain will allow bazel to download a specific python version, and use that version
@@ -92,8 +94,19 @@ load("@rules_python//python:pip.bzl", "pip_parse")
# You can instead check this `requirements.bzl` file into your repo.
pip_parse(
name = "pip",
- # Generate user friendly alias labels for each dependency that we have.
- incompatible_generate_aliases = True,
+
+ # Requirement groups allow Bazel to tolerate PyPi cycles by putting dependencies
+ # which are known to form cycles into groups together.
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ "sphinxcontrib-serializinghtml",
+ ],
+ },
# (Optional) You can provide a python_interpreter (path) or a python_interpreter_target (a Bazel target, that
# acts as an executable). The latter can be anything that could be used as Python interpreter. E.g.:
# 1. Python interpreter that you compile in the build file.
diff --git a/examples/build_file_generation/__init__.py b/examples/build_file_generation/__init__.py
index add73da..37dea1b 100644
--- a/examples/build_file_generation/__init__.py
+++ b/examples/build_file_generation/__init__.py
@@ -14,6 +14,7 @@
from flask import Flask, jsonify
from random_number_generator import generate_random_number
+import sphinx # noqa
app = Flask(__name__)
diff --git a/examples/build_file_generation/gazelle_python.yaml b/examples/build_file_generation/gazelle_python.yaml
index 1000757..6761b8d 100644
--- a/examples/build_file_generation/gazelle_python.yaml
+++ b/examples/build_file_generation/gazelle_python.yaml
@@ -5,6 +5,42 @@
manifest:
modules_mapping:
+ alabaster: alabaster
+ alabaster.support: alabaster
+ babel: Babel
+ babel.core: Babel
+ babel.dates: Babel
+ babel.languages: Babel
+ babel.lists: Babel
+ babel.localedata: Babel
+ babel.localtime: Babel
+ babel.messages: Babel
+ babel.messages.catalog: Babel
+ babel.messages.checkers: Babel
+ babel.messages.extract: Babel
+ babel.messages.frontend: Babel
+ babel.messages.jslexer: Babel
+ babel.messages.mofile: Babel
+ babel.messages.plurals: Babel
+ babel.messages.pofile: Babel
+ babel.numbers: Babel
+ babel.plural: Babel
+ babel.support: Babel
+ babel.units: Babel
+ babel.util: Babel
+ certifi: certifi
+ certifi.core: certifi
+ charset_normalizer: charset_normalizer
+ charset_normalizer.api: charset_normalizer
+ charset_normalizer.cd: charset_normalizer
+ charset_normalizer.cli: charset_normalizer
+ charset_normalizer.constant: charset_normalizer
+ charset_normalizer.legacy: charset_normalizer
+ charset_normalizer.md: charset_normalizer
+ charset_normalizer.md__mypyc: charset_normalizer
+ charset_normalizer.models: charset_normalizer
+ charset_normalizer.utils: charset_normalizer
+ charset_normalizer.version: charset_normalizer
click: click
click.core: click
click.decorators: click
@@ -17,6 +53,128 @@ manifest:
click.testing: click
click.types: click
click.utils: click
+ docutils: docutils
+ docutils.core: docutils
+ docutils.examples: docutils
+ docutils.frontend: docutils
+ docutils.io: docutils
+ docutils.languages: docutils
+ docutils.languages.af: docutils
+ docutils.languages.ar: docutils
+ docutils.languages.ca: docutils
+ docutils.languages.cs: docutils
+ docutils.languages.da: docutils
+ docutils.languages.de: docutils
+ docutils.languages.en: docutils
+ docutils.languages.eo: docutils
+ docutils.languages.es: docutils
+ docutils.languages.fa: docutils
+ docutils.languages.fi: docutils
+ docutils.languages.fr: docutils
+ docutils.languages.gl: docutils
+ docutils.languages.he: docutils
+ docutils.languages.it: docutils
+ docutils.languages.ja: docutils
+ docutils.languages.ko: docutils
+ docutils.languages.lt: docutils
+ docutils.languages.lv: docutils
+ docutils.languages.nl: docutils
+ docutils.languages.pl: docutils
+ docutils.languages.pt_br: docutils
+ docutils.languages.ru: docutils
+ docutils.languages.sk: docutils
+ docutils.languages.sv: docutils
+ docutils.languages.uk: docutils
+ docutils.languages.zh_cn: docutils
+ docutils.languages.zh_tw: docutils
+ docutils.nodes: docutils
+ docutils.parsers: docutils
+ docutils.parsers.commonmark_wrapper: docutils
+ docutils.parsers.null: docutils
+ docutils.parsers.recommonmark_wrapper: docutils
+ docutils.parsers.rst: docutils
+ docutils.parsers.rst.directives: docutils
+ docutils.parsers.rst.directives.admonitions: docutils
+ docutils.parsers.rst.directives.body: docutils
+ docutils.parsers.rst.directives.html: docutils
+ docutils.parsers.rst.directives.images: docutils
+ docutils.parsers.rst.directives.misc: docutils
+ docutils.parsers.rst.directives.parts: docutils
+ docutils.parsers.rst.directives.references: docutils
+ docutils.parsers.rst.directives.tables: docutils
+ docutils.parsers.rst.languages: docutils
+ docutils.parsers.rst.languages.af: docutils
+ docutils.parsers.rst.languages.ar: docutils
+ docutils.parsers.rst.languages.ca: docutils
+ docutils.parsers.rst.languages.cs: docutils
+ docutils.parsers.rst.languages.da: docutils
+ docutils.parsers.rst.languages.de: docutils
+ docutils.parsers.rst.languages.en: docutils
+ docutils.parsers.rst.languages.eo: docutils
+ docutils.parsers.rst.languages.es: docutils
+ docutils.parsers.rst.languages.fa: docutils
+ docutils.parsers.rst.languages.fi: docutils
+ docutils.parsers.rst.languages.fr: docutils
+ docutils.parsers.rst.languages.gl: docutils
+ docutils.parsers.rst.languages.he: docutils
+ docutils.parsers.rst.languages.it: docutils
+ docutils.parsers.rst.languages.ja: docutils
+ docutils.parsers.rst.languages.ko: docutils
+ docutils.parsers.rst.languages.lt: docutils
+ docutils.parsers.rst.languages.lv: docutils
+ docutils.parsers.rst.languages.nl: docutils
+ docutils.parsers.rst.languages.pl: docutils
+ docutils.parsers.rst.languages.pt_br: docutils
+ docutils.parsers.rst.languages.ru: docutils
+ docutils.parsers.rst.languages.sk: docutils
+ docutils.parsers.rst.languages.sv: docutils
+ docutils.parsers.rst.languages.uk: docutils
+ docutils.parsers.rst.languages.zh_cn: docutils
+ docutils.parsers.rst.languages.zh_tw: docutils
+ docutils.parsers.rst.roles: docutils
+ docutils.parsers.rst.states: docutils
+ docutils.parsers.rst.tableparser: docutils
+ docutils.readers: docutils
+ docutils.readers.doctree: docutils
+ docutils.readers.pep: docutils
+ docutils.readers.standalone: docutils
+ docutils.statemachine: docutils
+ docutils.transforms: docutils
+ docutils.transforms.components: docutils
+ docutils.transforms.frontmatter: docutils
+ docutils.transforms.misc: docutils
+ docutils.transforms.parts: docutils
+ docutils.transforms.peps: docutils
+ docutils.transforms.references: docutils
+ docutils.transforms.universal: docutils
+ docutils.transforms.writer_aux: docutils
+ docutils.utils: docutils
+ docutils.utils.code_analyzer: docutils
+ docutils.utils.error_reporting: docutils
+ docutils.utils.math: docutils
+ docutils.utils.math.latex2mathml: docutils
+ docutils.utils.math.math2html: docutils
+ docutils.utils.math.tex2mathml_extern: docutils
+ docutils.utils.math.tex2unichar: docutils
+ docutils.utils.math.unichar2tex: docutils
+ docutils.utils.punctuation_chars: docutils
+ docutils.utils.roman: docutils
+ docutils.utils.smartquotes: docutils
+ docutils.utils.urischemes: docutils
+ docutils.writers: docutils
+ docutils.writers.docutils_xml: docutils
+ docutils.writers.html4css1: docutils
+ docutils.writers.html5_polyglot: docutils
+ docutils.writers.latex2e: docutils
+ docutils.writers.manpage: docutils
+ docutils.writers.null: docutils
+ docutils.writers.odf_odt: docutils
+ docutils.writers.odf_odt.prepstyles: docutils
+ docutils.writers.odf_odt.pygmentsformatter: docutils
+ docutils.writers.pep_html: docutils
+ docutils.writers.pseudoxml: docutils
+ docutils.writers.s5_html: docutils
+ docutils.writers.xetex: docutils
flask: Flask
flask.app: Flask
flask.blueprints: Flask
@@ -38,6 +196,16 @@ manifest:
flask.typing: Flask
flask.views: Flask
flask.wrappers: Flask
+ idna: idna
+ idna.codec: idna
+ idna.compat: idna
+ idna.core: idna
+ idna.idnadata: idna
+ idna.intranges: idna
+ idna.package_data: idna
+ idna.uts46data: idna
+ imagesize: imagesize
+ imagesize.imagesize: imagesize
importlib_metadata: importlib_metadata
itsdangerous: itsdangerous
itsdangerous.encoding: itsdangerous
@@ -70,6 +238,548 @@ manifest:
jinja2.utils: Jinja2
jinja2.visitor: Jinja2
markupsafe: MarkupSafe
+ packaging: packaging
+ packaging.markers: packaging
+ packaging.metadata: packaging
+ packaging.requirements: packaging
+ packaging.specifiers: packaging
+ packaging.tags: packaging
+ packaging.utils: packaging
+ packaging.version: packaging
+ pygments: Pygments
+ pygments.cmdline: Pygments
+ pygments.console: Pygments
+ pygments.filter: Pygments
+ pygments.filters: Pygments
+ pygments.formatter: Pygments
+ pygments.formatters: Pygments
+ pygments.formatters.bbcode: Pygments
+ pygments.formatters.groff: Pygments
+ pygments.formatters.html: Pygments
+ pygments.formatters.img: Pygments
+ pygments.formatters.irc: Pygments
+ pygments.formatters.latex: Pygments
+ pygments.formatters.other: Pygments
+ pygments.formatters.pangomarkup: Pygments
+ pygments.formatters.rtf: Pygments
+ pygments.formatters.svg: Pygments
+ pygments.formatters.terminal: Pygments
+ pygments.formatters.terminal256: Pygments
+ pygments.lexer: Pygments
+ pygments.lexers: Pygments
+ pygments.lexers.actionscript: Pygments
+ pygments.lexers.ada: Pygments
+ pygments.lexers.agile: Pygments
+ pygments.lexers.algebra: Pygments
+ pygments.lexers.ambient: Pygments
+ pygments.lexers.amdgpu: Pygments
+ pygments.lexers.ampl: Pygments
+ pygments.lexers.apdlexer: Pygments
+ pygments.lexers.apl: Pygments
+ pygments.lexers.archetype: Pygments
+ pygments.lexers.arrow: Pygments
+ pygments.lexers.arturo: Pygments
+ pygments.lexers.asc: Pygments
+ pygments.lexers.asm: Pygments
+ pygments.lexers.asn1: Pygments
+ pygments.lexers.automation: Pygments
+ pygments.lexers.bare: Pygments
+ pygments.lexers.basic: Pygments
+ pygments.lexers.bdd: Pygments
+ pygments.lexers.berry: Pygments
+ pygments.lexers.bibtex: Pygments
+ pygments.lexers.blueprint: Pygments
+ pygments.lexers.boa: Pygments
+ pygments.lexers.bqn: Pygments
+ pygments.lexers.business: Pygments
+ pygments.lexers.c_cpp: Pygments
+ pygments.lexers.c_like: Pygments
+ pygments.lexers.capnproto: Pygments
+ pygments.lexers.carbon: Pygments
+ pygments.lexers.cddl: Pygments
+ pygments.lexers.chapel: Pygments
+ pygments.lexers.clean: Pygments
+ pygments.lexers.comal: Pygments
+ pygments.lexers.compiled: Pygments
+ pygments.lexers.configs: Pygments
+ pygments.lexers.console: Pygments
+ pygments.lexers.cplint: Pygments
+ pygments.lexers.crystal: Pygments
+ pygments.lexers.csound: Pygments
+ pygments.lexers.css: Pygments
+ pygments.lexers.d: Pygments
+ pygments.lexers.dalvik: Pygments
+ pygments.lexers.data: Pygments
+ pygments.lexers.dax: Pygments
+ pygments.lexers.devicetree: Pygments
+ pygments.lexers.diff: Pygments
+ pygments.lexers.dns: Pygments
+ pygments.lexers.dotnet: Pygments
+ pygments.lexers.dsls: Pygments
+ pygments.lexers.dylan: Pygments
+ pygments.lexers.ecl: Pygments
+ pygments.lexers.eiffel: Pygments
+ pygments.lexers.elm: Pygments
+ pygments.lexers.elpi: Pygments
+ pygments.lexers.email: Pygments
+ pygments.lexers.erlang: Pygments
+ pygments.lexers.esoteric: Pygments
+ pygments.lexers.ezhil: Pygments
+ pygments.lexers.factor: Pygments
+ pygments.lexers.fantom: Pygments
+ pygments.lexers.felix: Pygments
+ pygments.lexers.fift: Pygments
+ pygments.lexers.floscript: Pygments
+ pygments.lexers.forth: Pygments
+ pygments.lexers.fortran: Pygments
+ pygments.lexers.foxpro: Pygments
+ pygments.lexers.freefem: Pygments
+ pygments.lexers.func: Pygments
+ pygments.lexers.functional: Pygments
+ pygments.lexers.futhark: Pygments
+ pygments.lexers.gcodelexer: Pygments
+ pygments.lexers.gdscript: Pygments
+ pygments.lexers.go: Pygments
+ pygments.lexers.grammar_notation: Pygments
+ pygments.lexers.graph: Pygments
+ pygments.lexers.graphics: Pygments
+ pygments.lexers.graphql: Pygments
+ pygments.lexers.graphviz: Pygments
+ pygments.lexers.gsql: Pygments
+ pygments.lexers.haskell: Pygments
+ pygments.lexers.haxe: Pygments
+ pygments.lexers.hdl: Pygments
+ pygments.lexers.hexdump: Pygments
+ pygments.lexers.html: Pygments
+ pygments.lexers.idl: Pygments
+ pygments.lexers.igor: Pygments
+ pygments.lexers.inferno: Pygments
+ pygments.lexers.installers: Pygments
+ pygments.lexers.int_fiction: Pygments
+ pygments.lexers.iolang: Pygments
+ pygments.lexers.j: Pygments
+ pygments.lexers.javascript: Pygments
+ pygments.lexers.jmespath: Pygments
+ pygments.lexers.jslt: Pygments
+ pygments.lexers.jsonnet: Pygments
+ pygments.lexers.julia: Pygments
+ pygments.lexers.jvm: Pygments
+ pygments.lexers.kuin: Pygments
+ pygments.lexers.lilypond: Pygments
+ pygments.lexers.lisp: Pygments
+ pygments.lexers.macaulay2: Pygments
+ pygments.lexers.make: Pygments
+ pygments.lexers.markup: Pygments
+ pygments.lexers.math: Pygments
+ pygments.lexers.matlab: Pygments
+ pygments.lexers.maxima: Pygments
+ pygments.lexers.meson: Pygments
+ pygments.lexers.mime: Pygments
+ pygments.lexers.minecraft: Pygments
+ pygments.lexers.mips: Pygments
+ pygments.lexers.ml: Pygments
+ pygments.lexers.modeling: Pygments
+ pygments.lexers.modula2: Pygments
+ pygments.lexers.monte: Pygments
+ pygments.lexers.mosel: Pygments
+ pygments.lexers.ncl: Pygments
+ pygments.lexers.nimrod: Pygments
+ pygments.lexers.nit: Pygments
+ pygments.lexers.nix: Pygments
+ pygments.lexers.oberon: Pygments
+ pygments.lexers.objective: Pygments
+ pygments.lexers.ooc: Pygments
+ pygments.lexers.openscad: Pygments
+ pygments.lexers.other: Pygments
+ pygments.lexers.parasail: Pygments
+ pygments.lexers.parsers: Pygments
+ pygments.lexers.pascal: Pygments
+ pygments.lexers.pawn: Pygments
+ pygments.lexers.perl: Pygments
+ pygments.lexers.phix: Pygments
+ pygments.lexers.php: Pygments
+ pygments.lexers.pointless: Pygments
+ pygments.lexers.pony: Pygments
+ pygments.lexers.praat: Pygments
+ pygments.lexers.procfile: Pygments
+ pygments.lexers.prolog: Pygments
+ pygments.lexers.promql: Pygments
+ pygments.lexers.ptx: Pygments
+ pygments.lexers.python: Pygments
+ pygments.lexers.q: Pygments
+ pygments.lexers.qlik: Pygments
+ pygments.lexers.qvt: Pygments
+ pygments.lexers.r: Pygments
+ pygments.lexers.rdf: Pygments
+ pygments.lexers.rebol: Pygments
+ pygments.lexers.resource: Pygments
+ pygments.lexers.ride: Pygments
+ pygments.lexers.rita: Pygments
+ pygments.lexers.rnc: Pygments
+ pygments.lexers.roboconf: Pygments
+ pygments.lexers.robotframework: Pygments
+ pygments.lexers.ruby: Pygments
+ pygments.lexers.rust: Pygments
+ pygments.lexers.sas: Pygments
+ pygments.lexers.savi: Pygments
+ pygments.lexers.scdoc: Pygments
+ pygments.lexers.scripting: Pygments
+ pygments.lexers.sgf: Pygments
+ pygments.lexers.shell: Pygments
+ pygments.lexers.sieve: Pygments
+ pygments.lexers.slash: Pygments
+ pygments.lexers.smalltalk: Pygments
+ pygments.lexers.smithy: Pygments
+ pygments.lexers.smv: Pygments
+ pygments.lexers.snobol: Pygments
+ pygments.lexers.solidity: Pygments
+ pygments.lexers.sophia: Pygments
+ pygments.lexers.special: Pygments
+ pygments.lexers.spice: Pygments
+ pygments.lexers.sql: Pygments
+ pygments.lexers.srcinfo: Pygments
+ pygments.lexers.stata: Pygments
+ pygments.lexers.supercollider: Pygments
+ pygments.lexers.tal: Pygments
+ pygments.lexers.tcl: Pygments
+ pygments.lexers.teal: Pygments
+ pygments.lexers.templates: Pygments
+ pygments.lexers.teraterm: Pygments
+ pygments.lexers.testing: Pygments
+ pygments.lexers.text: Pygments
+ pygments.lexers.textedit: Pygments
+ pygments.lexers.textfmts: Pygments
+ pygments.lexers.theorem: Pygments
+ pygments.lexers.thingsdb: Pygments
+ pygments.lexers.tlb: Pygments
+ pygments.lexers.tls: Pygments
+ pygments.lexers.tnt: Pygments
+ pygments.lexers.trafficscript: Pygments
+ pygments.lexers.typoscript: Pygments
+ pygments.lexers.ul4: Pygments
+ pygments.lexers.unicon: Pygments
+ pygments.lexers.urbi: Pygments
+ pygments.lexers.usd: Pygments
+ pygments.lexers.varnish: Pygments
+ pygments.lexers.verification: Pygments
+ pygments.lexers.verifpal: Pygments
+ pygments.lexers.web: Pygments
+ pygments.lexers.webassembly: Pygments
+ pygments.lexers.webidl: Pygments
+ pygments.lexers.webmisc: Pygments
+ pygments.lexers.wgsl: Pygments
+ pygments.lexers.whiley: Pygments
+ pygments.lexers.wowtoc: Pygments
+ pygments.lexers.wren: Pygments
+ pygments.lexers.x10: Pygments
+ pygments.lexers.xorg: Pygments
+ pygments.lexers.yang: Pygments
+ pygments.lexers.yara: Pygments
+ pygments.lexers.zig: Pygments
+ pygments.modeline: Pygments
+ pygments.plugin: Pygments
+ pygments.regexopt: Pygments
+ pygments.scanner: Pygments
+ pygments.sphinxext: Pygments
+ pygments.style: Pygments
+ pygments.styles: Pygments
+ pygments.styles.abap: Pygments
+ pygments.styles.algol: Pygments
+ pygments.styles.algol_nu: Pygments
+ pygments.styles.arduino: Pygments
+ pygments.styles.autumn: Pygments
+ pygments.styles.borland: Pygments
+ pygments.styles.bw: Pygments
+ pygments.styles.colorful: Pygments
+ pygments.styles.default: Pygments
+ pygments.styles.dracula: Pygments
+ pygments.styles.emacs: Pygments
+ pygments.styles.friendly: Pygments
+ pygments.styles.friendly_grayscale: Pygments
+ pygments.styles.fruity: Pygments
+ pygments.styles.gh_dark: Pygments
+ pygments.styles.gruvbox: Pygments
+ pygments.styles.igor: Pygments
+ pygments.styles.inkpot: Pygments
+ pygments.styles.lightbulb: Pygments
+ pygments.styles.lilypond: Pygments
+ pygments.styles.lovelace: Pygments
+ pygments.styles.manni: Pygments
+ pygments.styles.material: Pygments
+ pygments.styles.monokai: Pygments
+ pygments.styles.murphy: Pygments
+ pygments.styles.native: Pygments
+ pygments.styles.nord: Pygments
+ pygments.styles.onedark: Pygments
+ pygments.styles.paraiso_dark: Pygments
+ pygments.styles.paraiso_light: Pygments
+ pygments.styles.pastie: Pygments
+ pygments.styles.perldoc: Pygments
+ pygments.styles.rainbow_dash: Pygments
+ pygments.styles.rrt: Pygments
+ pygments.styles.sas: Pygments
+ pygments.styles.solarized: Pygments
+ pygments.styles.staroffice: Pygments
+ pygments.styles.stata_dark: Pygments
+ pygments.styles.stata_light: Pygments
+ pygments.styles.tango: Pygments
+ pygments.styles.trac: Pygments
+ pygments.styles.vim: Pygments
+ pygments.styles.vs: Pygments
+ pygments.styles.xcode: Pygments
+ pygments.styles.zenburn: Pygments
+ pygments.token: Pygments
+ pygments.unistring: Pygments
+ pygments.util: Pygments
+ 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
+ snowballstemmer: snowballstemmer
+ snowballstemmer.among: snowballstemmer
+ snowballstemmer.arabic_stemmer: snowballstemmer
+ snowballstemmer.armenian_stemmer: snowballstemmer
+ snowballstemmer.basestemmer: snowballstemmer
+ snowballstemmer.basque_stemmer: snowballstemmer
+ snowballstemmer.catalan_stemmer: snowballstemmer
+ snowballstemmer.danish_stemmer: snowballstemmer
+ snowballstemmer.dutch_stemmer: snowballstemmer
+ snowballstemmer.english_stemmer: snowballstemmer
+ snowballstemmer.finnish_stemmer: snowballstemmer
+ snowballstemmer.french_stemmer: snowballstemmer
+ snowballstemmer.german_stemmer: snowballstemmer
+ snowballstemmer.greek_stemmer: snowballstemmer
+ snowballstemmer.hindi_stemmer: snowballstemmer
+ snowballstemmer.hungarian_stemmer: snowballstemmer
+ snowballstemmer.indonesian_stemmer: snowballstemmer
+ snowballstemmer.irish_stemmer: snowballstemmer
+ snowballstemmer.italian_stemmer: snowballstemmer
+ snowballstemmer.lithuanian_stemmer: snowballstemmer
+ snowballstemmer.nepali_stemmer: snowballstemmer
+ snowballstemmer.norwegian_stemmer: snowballstemmer
+ snowballstemmer.porter_stemmer: snowballstemmer
+ snowballstemmer.portuguese_stemmer: snowballstemmer
+ snowballstemmer.romanian_stemmer: snowballstemmer
+ snowballstemmer.russian_stemmer: snowballstemmer
+ snowballstemmer.serbian_stemmer: snowballstemmer
+ snowballstemmer.spanish_stemmer: snowballstemmer
+ snowballstemmer.swedish_stemmer: snowballstemmer
+ snowballstemmer.tamil_stemmer: snowballstemmer
+ snowballstemmer.turkish_stemmer: snowballstemmer
+ snowballstemmer.yiddish_stemmer: snowballstemmer
+ sphinx: sphinx
+ sphinx.addnodes: sphinx
+ sphinx.application: sphinx
+ sphinx.builders: sphinx
+ sphinx.builders.changes: sphinx
+ sphinx.builders.dirhtml: sphinx
+ sphinx.builders.dummy: sphinx
+ sphinx.builders.epub3: sphinx
+ sphinx.builders.gettext: sphinx
+ sphinx.builders.html: sphinx
+ sphinx.builders.html.transforms: sphinx
+ sphinx.builders.latex: sphinx
+ sphinx.builders.latex.constants: sphinx
+ sphinx.builders.latex.nodes: sphinx
+ sphinx.builders.latex.theming: sphinx
+ sphinx.builders.latex.transforms: sphinx
+ sphinx.builders.latex.util: sphinx
+ sphinx.builders.linkcheck: sphinx
+ sphinx.builders.manpage: sphinx
+ sphinx.builders.singlehtml: sphinx
+ sphinx.builders.texinfo: sphinx
+ sphinx.builders.text: sphinx
+ sphinx.builders.xml: sphinx
+ sphinx.cmd: sphinx
+ sphinx.cmd.build: sphinx
+ sphinx.cmd.make_mode: sphinx
+ sphinx.cmd.quickstart: sphinx
+ sphinx.config: sphinx
+ sphinx.deprecation: sphinx
+ sphinx.directives: sphinx
+ sphinx.directives.code: sphinx
+ sphinx.directives.other: sphinx
+ sphinx.directives.patches: sphinx
+ sphinx.domains: sphinx
+ sphinx.domains.c: sphinx
+ sphinx.domains.changeset: sphinx
+ sphinx.domains.citation: sphinx
+ sphinx.domains.cpp: sphinx
+ sphinx.domains.index: sphinx
+ sphinx.domains.javascript: sphinx
+ sphinx.domains.math: sphinx
+ sphinx.domains.python: sphinx
+ sphinx.domains.rst: sphinx
+ sphinx.domains.std: sphinx
+ sphinx.environment: sphinx
+ sphinx.environment.adapters: sphinx
+ sphinx.environment.adapters.asset: sphinx
+ sphinx.environment.adapters.indexentries: sphinx
+ sphinx.environment.adapters.toctree: sphinx
+ sphinx.environment.collectors: sphinx
+ sphinx.environment.collectors.asset: sphinx
+ sphinx.environment.collectors.dependencies: sphinx
+ sphinx.environment.collectors.metadata: sphinx
+ sphinx.environment.collectors.title: sphinx
+ sphinx.environment.collectors.toctree: sphinx
+ sphinx.errors: sphinx
+ sphinx.events: sphinx
+ sphinx.ext: sphinx
+ sphinx.ext.apidoc: sphinx
+ sphinx.ext.autodoc: sphinx
+ sphinx.ext.autodoc.directive: sphinx
+ sphinx.ext.autodoc.importer: sphinx
+ sphinx.ext.autodoc.mock: sphinx
+ sphinx.ext.autodoc.preserve_defaults: sphinx
+ sphinx.ext.autodoc.type_comment: sphinx
+ sphinx.ext.autodoc.typehints: sphinx
+ sphinx.ext.autosectionlabel: sphinx
+ sphinx.ext.autosummary: sphinx
+ sphinx.ext.autosummary.generate: sphinx
+ sphinx.ext.coverage: sphinx
+ sphinx.ext.doctest: sphinx
+ sphinx.ext.duration: sphinx
+ sphinx.ext.extlinks: sphinx
+ sphinx.ext.githubpages: sphinx
+ sphinx.ext.graphviz: sphinx
+ sphinx.ext.ifconfig: sphinx
+ sphinx.ext.imgconverter: sphinx
+ sphinx.ext.imgmath: sphinx
+ sphinx.ext.inheritance_diagram: sphinx
+ sphinx.ext.intersphinx: sphinx
+ sphinx.ext.linkcode: sphinx
+ sphinx.ext.mathjax: sphinx
+ sphinx.ext.napoleon: sphinx
+ sphinx.ext.napoleon.docstring: sphinx
+ sphinx.ext.todo: sphinx
+ sphinx.ext.viewcode: sphinx
+ sphinx.extension: sphinx
+ sphinx.highlighting: sphinx
+ sphinx.io: sphinx
+ sphinx.jinja2glue: sphinx
+ sphinx.locale: sphinx
+ sphinx.parsers: sphinx
+ sphinx.project: sphinx
+ sphinx.pycode: sphinx
+ sphinx.pycode.ast: sphinx
+ sphinx.pycode.parser: sphinx
+ sphinx.pygments_styles: sphinx
+ sphinx.registry: sphinx
+ sphinx.roles: sphinx
+ sphinx.search: sphinx
+ sphinx.search.da: sphinx
+ sphinx.search.de: sphinx
+ sphinx.search.en: sphinx
+ sphinx.search.es: sphinx
+ sphinx.search.fi: sphinx
+ sphinx.search.fr: sphinx
+ sphinx.search.hu: sphinx
+ sphinx.search.it: sphinx
+ sphinx.search.ja: sphinx
+ sphinx.search.nl: sphinx
+ sphinx.search.no: sphinx
+ sphinx.search.pt: sphinx
+ sphinx.search.ro: sphinx
+ sphinx.search.ru: sphinx
+ sphinx.search.sv: sphinx
+ sphinx.search.tr: sphinx
+ sphinx.search.zh: sphinx
+ sphinx.testing: sphinx
+ sphinx.testing.fixtures: sphinx
+ sphinx.testing.path: sphinx
+ sphinx.testing.restructuredtext: sphinx
+ sphinx.testing.util: sphinx
+ sphinx.theming: sphinx
+ sphinx.transforms: sphinx
+ sphinx.transforms.compact_bullet_list: sphinx
+ sphinx.transforms.i18n: sphinx
+ sphinx.transforms.post_transforms: sphinx
+ sphinx.transforms.post_transforms.code: sphinx
+ sphinx.transforms.post_transforms.images: sphinx
+ sphinx.transforms.references: sphinx
+ sphinx.util: sphinx
+ sphinx.util.build_phase: sphinx
+ sphinx.util.cfamily: sphinx
+ sphinx.util.console: sphinx
+ sphinx.util.display: sphinx
+ sphinx.util.docfields: sphinx
+ sphinx.util.docstrings: sphinx
+ sphinx.util.docutils: sphinx
+ sphinx.util.exceptions: sphinx
+ sphinx.util.fileutil: sphinx
+ sphinx.util.http_date: sphinx
+ sphinx.util.i18n: sphinx
+ sphinx.util.images: sphinx
+ sphinx.util.index_entries: sphinx
+ sphinx.util.inspect: sphinx
+ sphinx.util.inventory: sphinx
+ sphinx.util.logging: sphinx
+ sphinx.util.matching: sphinx
+ sphinx.util.math: sphinx
+ sphinx.util.nodes: sphinx
+ sphinx.util.osutil: sphinx
+ sphinx.util.parallel: sphinx
+ sphinx.util.png: sphinx
+ sphinx.util.requests: sphinx
+ sphinx.util.rst: sphinx
+ sphinx.util.tags: sphinx
+ sphinx.util.template: sphinx
+ sphinx.util.texescape: sphinx
+ sphinx.util.typing: sphinx
+ sphinx.versioning: sphinx
+ sphinx.writers: sphinx
+ sphinx.writers.html: sphinx
+ sphinx.writers.html5: sphinx
+ sphinx.writers.latex: sphinx
+ sphinx.writers.manpage: sphinx
+ sphinx.writers.texinfo: sphinx
+ sphinx.writers.text: sphinx
+ sphinx.writers.xml: sphinx
+ sphinxcontrib.applehelp: sphinxcontrib_applehelp
+ sphinxcontrib.devhelp: sphinxcontrib_devhelp
+ sphinxcontrib.htmlhelp: sphinxcontrib_htmlhelp
+ sphinxcontrib.jsmath: sphinxcontrib_jsmath
+ sphinxcontrib.jsmath.version: sphinxcontrib_jsmath
+ sphinxcontrib.qthelp: sphinxcontrib_qthelp
+ sphinxcontrib.serializinghtml: sphinxcontrib_serializinghtml
+ sphinxcontrib.serializinghtml.jsonimpl: sphinxcontrib_serializinghtml
+ urllib3: urllib3
+ urllib3.connection: urllib3
+ urllib3.connectionpool: urllib3
+ urllib3.contrib: urllib3
+ urllib3.contrib.pyopenssl: urllib3
+ urllib3.contrib.securetransport: urllib3
+ urllib3.contrib.socks: urllib3
+ urllib3.exceptions: urllib3
+ urllib3.fields: urllib3
+ urllib3.filepost: urllib3
+ urllib3.poolmanager: urllib3
+ urllib3.response: urllib3
+ urllib3.util: urllib3
+ urllib3.util.connection: urllib3
+ urllib3.util.proxy: 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.util: urllib3
+ urllib3.util.wait: urllib3
werkzeug: Werkzeug
werkzeug.datastructures: Werkzeug
werkzeug.debug: Werkzeug
@@ -114,5 +824,4 @@ manifest:
zipp.py310compat: zipp
pip_repository:
name: pip
- use_pip_repository_aliases: true
-integrity: 030d6d99b56c32d6577e616b617260d0a93588af791269162e43391a5a4fa576
+integrity: 4658c69530ba1ee117da0c963c9c671041e1c470d938c31cdbbfccc21dd259cb
diff --git a/examples/build_file_generation/random_number_generator/BUILD.bazel b/examples/build_file_generation/random_number_generator/BUILD.bazel
index 95e16fd..28370b4 100644
--- a/examples/build_file_generation/random_number_generator/BUILD.bazel
+++ b/examples/build_file_generation/random_number_generator/BUILD.bazel
@@ -6,14 +6,12 @@ py_library(
"__init__.py",
"generate_random_number.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
py_test(
name = "random_number_generator_test",
srcs = ["__test__.py"],
- imports = [".."],
main = "__test__.py",
deps = [":random_number_generator"],
)
diff --git a/examples/build_file_generation/requirements.in b/examples/build_file_generation/requirements.in
index 7e10602..d1380fa 100644
--- a/examples/build_file_generation/requirements.in
+++ b/examples/build_file_generation/requirements.in
@@ -1 +1,3 @@
flask
+sphinx
+sphinxcontrib-serializinghtml
diff --git a/examples/build_file_generation/requirements_lock.txt b/examples/build_file_generation/requirements_lock.txt
index 443db71..995a56a 100644
--- a/examples/build_file_generation/requirements_lock.txt
+++ b/examples/build_file_generation/requirements_lock.txt
@@ -4,18 +4,136 @@
#
# bazel run //:requirements.update
#
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
+certifi==2023.7.22 \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+ # via requests
+charset-normalizer==3.3.1 \
+ --hash=sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5 \
+ --hash=sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93 \
+ --hash=sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a \
+ --hash=sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d \
+ --hash=sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c \
+ --hash=sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1 \
+ --hash=sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58 \
+ --hash=sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2 \
+ --hash=sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557 \
+ --hash=sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147 \
+ --hash=sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041 \
+ --hash=sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2 \
+ --hash=sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2 \
+ --hash=sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7 \
+ --hash=sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296 \
+ --hash=sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690 \
+ --hash=sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67 \
+ --hash=sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57 \
+ --hash=sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597 \
+ --hash=sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846 \
+ --hash=sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b \
+ --hash=sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97 \
+ --hash=sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c \
+ --hash=sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62 \
+ --hash=sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa \
+ --hash=sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f \
+ --hash=sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e \
+ --hash=sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821 \
+ --hash=sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3 \
+ --hash=sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4 \
+ --hash=sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb \
+ --hash=sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727 \
+ --hash=sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514 \
+ --hash=sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d \
+ --hash=sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761 \
+ --hash=sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55 \
+ --hash=sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f \
+ --hash=sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c \
+ --hash=sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034 \
+ --hash=sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6 \
+ --hash=sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae \
+ --hash=sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1 \
+ --hash=sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14 \
+ --hash=sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1 \
+ --hash=sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228 \
+ --hash=sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708 \
+ --hash=sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48 \
+ --hash=sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f \
+ --hash=sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5 \
+ --hash=sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f \
+ --hash=sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4 \
+ --hash=sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8 \
+ --hash=sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff \
+ --hash=sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61 \
+ --hash=sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b \
+ --hash=sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97 \
+ --hash=sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b \
+ --hash=sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605 \
+ --hash=sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728 \
+ --hash=sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d \
+ --hash=sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c \
+ --hash=sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf \
+ --hash=sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673 \
+ --hash=sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1 \
+ --hash=sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b \
+ --hash=sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41 \
+ --hash=sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8 \
+ --hash=sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f \
+ --hash=sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4 \
+ --hash=sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008 \
+ --hash=sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9 \
+ --hash=sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5 \
+ --hash=sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f \
+ --hash=sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e \
+ --hash=sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273 \
+ --hash=sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45 \
+ --hash=sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e \
+ --hash=sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656 \
+ --hash=sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e \
+ --hash=sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c \
+ --hash=sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2 \
+ --hash=sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72 \
+ --hash=sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056 \
+ --hash=sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397 \
+ --hash=sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42 \
+ --hash=sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd \
+ --hash=sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3 \
+ --hash=sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213 \
+ --hash=sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf \
+ --hash=sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67
+ # via requests
click==8.1.3 \
--hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
--hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
# via flask
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
flask==2.2.2 \
--hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
--hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
# via -r requirements.in
+idna==3.4 \
+ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
+ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
+ # via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
importlib-metadata==5.2.0 \
--hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
--hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
- # via flask
+ # via
+ # flask
+ # sphinx
itsdangerous==2.1.2 \
--hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
--hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
@@ -23,7 +141,9 @@ itsdangerous==2.1.2 \
jinja2==3.1.2 \
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
- # via flask
+ # via
+ # flask
+ # sphinx
markupsafe==2.1.1 \
--hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
--hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
@@ -68,6 +188,62 @@ markupsafe==2.1.1 \
# via
# jinja2
# werkzeug
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
+requests==2.31.0 \
+ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
+ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+ # via sphinx
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
+urllib3==2.0.7 \
+ --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \
+ --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e
+ # via requests
werkzeug==2.2.2 \
--hash=sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f \
--hash=sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5
diff --git a/examples/build_file_generation/requirements_windows.txt b/examples/build_file_generation/requirements_windows.txt
index bdd536f..1970969 100644
--- a/examples/build_file_generation/requirements_windows.txt
+++ b/examples/build_file_generation/requirements_windows.txt
@@ -1,82 +1,260 @@
-#
-# This file is autogenerated by pip-compile with Python 3.9
-# by the following command:
-#
-# bazel run //:requirements.update
-#
-click==8.1.3 \
- --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
- --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
- # via flask
-colorama==0.4.6 \
- --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
- --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
- # via click
-flask==2.2.2 \
- --hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
- --hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
- # via -r requirements.in
-importlib-metadata==5.2.0 \
- --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
- --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
- # via flask
-itsdangerous==2.1.2 \
- --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
- --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
- # via flask
-jinja2==3.1.2 \
- --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
- --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
- # via flask
-markupsafe==2.1.1 \
- --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
- --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
- --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
- --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
- --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
- --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
- --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
- --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
- --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
- --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
- --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
- --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
- --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
- --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
- --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
- --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
- --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
- --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
- --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
- --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
- --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
- --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
- --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
- --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
- --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
- --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
- --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
- --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
- --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
- --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
- --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
- --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
- --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
- --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
- --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
- --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
- --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
- --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
- --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
- --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
- # via
- # jinja2
- # werkzeug
-werkzeug==2.2.2 \
- --hash=sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f \
- --hash=sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5
- # via flask
-zipp==3.11.0 \
- --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \
- --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766
- # via importlib-metadata
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# bazel run //:requirements.update
+#
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
+certifi==2023.7.22 \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+ # via requests
+charset-normalizer==3.3.1 \
+ --hash=sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5 \
+ --hash=sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93 \
+ --hash=sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a \
+ --hash=sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d \
+ --hash=sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c \
+ --hash=sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1 \
+ --hash=sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58 \
+ --hash=sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2 \
+ --hash=sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557 \
+ --hash=sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147 \
+ --hash=sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041 \
+ --hash=sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2 \
+ --hash=sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2 \
+ --hash=sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7 \
+ --hash=sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296 \
+ --hash=sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690 \
+ --hash=sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67 \
+ --hash=sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57 \
+ --hash=sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597 \
+ --hash=sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846 \
+ --hash=sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b \
+ --hash=sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97 \
+ --hash=sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c \
+ --hash=sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62 \
+ --hash=sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa \
+ --hash=sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f \
+ --hash=sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e \
+ --hash=sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821 \
+ --hash=sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3 \
+ --hash=sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4 \
+ --hash=sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb \
+ --hash=sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727 \
+ --hash=sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514 \
+ --hash=sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d \
+ --hash=sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761 \
+ --hash=sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55 \
+ --hash=sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f \
+ --hash=sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c \
+ --hash=sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034 \
+ --hash=sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6 \
+ --hash=sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae \
+ --hash=sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1 \
+ --hash=sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14 \
+ --hash=sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1 \
+ --hash=sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228 \
+ --hash=sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708 \
+ --hash=sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48 \
+ --hash=sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f \
+ --hash=sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5 \
+ --hash=sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f \
+ --hash=sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4 \
+ --hash=sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8 \
+ --hash=sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff \
+ --hash=sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61 \
+ --hash=sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b \
+ --hash=sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97 \
+ --hash=sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b \
+ --hash=sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605 \
+ --hash=sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728 \
+ --hash=sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d \
+ --hash=sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c \
+ --hash=sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf \
+ --hash=sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673 \
+ --hash=sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1 \
+ --hash=sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b \
+ --hash=sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41 \
+ --hash=sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8 \
+ --hash=sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f \
+ --hash=sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4 \
+ --hash=sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008 \
+ --hash=sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9 \
+ --hash=sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5 \
+ --hash=sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f \
+ --hash=sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e \
+ --hash=sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273 \
+ --hash=sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45 \
+ --hash=sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e \
+ --hash=sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656 \
+ --hash=sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e \
+ --hash=sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c \
+ --hash=sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2 \
+ --hash=sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72 \
+ --hash=sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056 \
+ --hash=sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397 \
+ --hash=sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42 \
+ --hash=sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd \
+ --hash=sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3 \
+ --hash=sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213 \
+ --hash=sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf \
+ --hash=sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67
+ # via requests
+click==8.1.3 \
+ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
+ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
+ # via flask
+colorama==0.4.6 \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+ # via
+ # click
+ # sphinx
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
+flask==2.2.2 \
+ --hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
+ --hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
+ # via -r requirements.in
+idna==3.4 \
+ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
+ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
+ # via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
+importlib-metadata==5.2.0 \
+ --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
+ --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
+ # via
+ # flask
+ # sphinx
+itsdangerous==2.1.2 \
+ --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
+ --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
+ # via flask
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via
+ # flask
+ # sphinx
+markupsafe==2.1.1 \
+ --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
+ --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
+ --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
+ --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
+ --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
+ --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
+ --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
+ --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
+ --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
+ --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
+ --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
+ --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
+ --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
+ --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
+ --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
+ --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
+ --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
+ --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
+ --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
+ --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
+ --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
+ --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
+ --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
+ --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
+ --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
+ --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
+ --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
+ --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
+ --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
+ --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
+ --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
+ --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
+ --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
+ --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
+ --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
+ --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
+ --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
+ --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
+ --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
+ --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
+ # via
+ # jinja2
+ # werkzeug
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
+requests==2.31.0 \
+ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
+ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+ # via sphinx
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
+urllib3==2.0.7 \
+ --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \
+ --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e
+ # via requests
+werkzeug==2.2.2 \
+ --hash=sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f \
+ --hash=sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5
+ # via flask
+zipp==3.11.0 \
+ --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \
+ --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766
+ # via importlib-metadata
diff --git a/examples/bzlmod/BUILD.bazel b/examples/bzlmod/BUILD.bazel
index 3db7751..bb16f98 100644
--- a/examples/bzlmod/BUILD.bazel
+++ b/examples/bzlmod/BUILD.bazel
@@ -16,8 +16,7 @@ load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
# with pip-compile.
compile_pip_requirements_3_9(
name = "requirements_3_9",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock_3_9.txt",
requirements_windows = "requirements_windows_3_9.txt",
)
@@ -26,8 +25,8 @@ compile_pip_requirements_3_9(
# with pip-compile.
compile_pip_requirements_3_10(
name = "requirements_3_10",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ timeout = "moderate",
+ src = "requirements.in",
requirements_txt = "requirements_lock_3_10.txt",
requirements_windows = "requirements_windows_3_10.txt",
)
@@ -41,6 +40,7 @@ py_library(
name = "lib",
srcs = ["lib.py"],
deps = [
+ requirement("sphinx"),
requirement("pylint"),
requirement("tabulate"),
requirement("python-dateutil"),
diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel
index df88ae8..e49b586 100644
--- a/examples/bzlmod/MODULE.bazel
+++ b/examples/bzlmod/MODULE.bazel
@@ -11,9 +11,11 @@ local_path_override(
path = "../..",
)
-# Setting python.toolchain is optional as rules_python
-# sets a toolchain for you, using the latest supported version
-# of Python. We do recomend that you set a version here.
+# (py_proto_library specific) We are using rules_proto to define rules_proto targets to be consumed by py_proto_library.
+bazel_dep(name = "rules_proto", version = "5.3.0-21.7")
+
+# (py_proto_library specific) Add the protobuf library for well-known types (e.g. `Any`, `Timestamp`, etc)
+bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf")
# We next initialize the python toolchain using the extension.
# You can set different Python versions in this block.
@@ -91,10 +93,26 @@ use_repo(pip, "whl_mods_hub")
# call.
# Alternatively, `python_interpreter_target` can be used to directly specify
# the Python interpreter to run to resolve dependencies.
-# Because we do not have a python_version defined here
-# pip.parse uses the python toolchain that is set as default.
pip.parse(
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ "sphinxcontrib-serializinghtml",
+ ],
+ },
+ # You can use one of the values below to specify the target platform
+ # to generate the dependency graph for.
+ experimental_target_platforms = [
+ "all",
+ "linux_*",
+ "host",
+ ],
hub_name = "pip",
+ python_version = "3.9",
requirements_lock = "//:requirements_lock_3_9.txt",
requirements_windows = "//:requirements_windows_3_9.txt",
# These modifications were created above and we
@@ -106,6 +124,23 @@ pip.parse(
},
)
pip.parse(
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ "sphinxcontrib-serializinghtml",
+ ],
+ },
+ # You can use one of the values below to specify the target platform
+ # to generate the dependency graph for.
+ experimental_target_platforms = [
+ "all",
+ "linux_*",
+ "host",
+ ],
hub_name = "pip",
python_version = "3.10",
requirements_lock = "//:requirements_lock_3_10.txt",
@@ -119,12 +154,33 @@ pip.parse(
},
)
-# NOTE: The pip_39 repo is only used because the plain `@pip` repo doesn't
-# yet support entry points; see https://github.com/bazelbuild/rules_python/issues/1262
-use_repo(pip, "pip", "pip_39")
+# You can add patches that will be applied on the whl contents.
+#
+# The patches have to be in the unified-diff format.
+pip.override(
+ file = "requests-2.25.1-py2.py3-none-any.whl",
+ patch_strip = 1,
+ patches = [
+ "@//patches:empty.patch",
+ "@//patches:requests_metadata.patch",
+ "@//patches:requests_record.patch",
+ ],
+)
+use_repo(pip, "pip")
bazel_dep(name = "other_module", version = "", repo_name = "our_other_module")
local_path_override(
module_name = "other_module",
path = "other_module",
)
+
+# =====
+# Config for testing duplicate packages in requirements
+# =====
+#
+pip.parse(
+ hub_name = "dupe_requirements",
+ python_version = "3.9", # Must match whatever is marked is_default=True
+ requirements_lock = "//tests/dupe_requirements:requirements.txt",
+)
+use_repo(pip, "dupe_requirements")
diff --git a/examples/bzlmod/MODULE.bazel.lock b/examples/bzlmod/MODULE.bazel.lock
new file mode 100644
index 0000000..dbdc3b1
--- /dev/null
+++ b/examples/bzlmod/MODULE.bazel.lock
@@ -0,0 +1,4157 @@
+{
+ "lockFileVersion": 3,
+ "moduleFileHash": "e369c446c373fa9ee4c990e4e4b92242b7c3c555931d533880da24aa248d8997",
+ "flags": {
+ "cmdRegistries": [
+ "https://bcr.bazel.build/"
+ ],
+ "cmdModuleOverrides": {},
+ "allowedYankedVersions": [],
+ "envVarAllowedYankedVersions": "",
+ "ignoreDevDependency": false,
+ "directDependenciesMode": "WARNING",
+ "compatibilityMode": "ERROR"
+ },
+ "localOverrideHashes": {
+ "other_module": "a923862b93886a355d86edd0b07294b418337deafb325ca55b2b20ace6ab48d3",
+ "rules_python": "9c72d3982a66312a41d6e5e0480248e28ad81ffd240675f06b38775f2759d027",
+ "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787"
+ },
+ "moduleDepGraph": {
+ "<root>": {
+ "name": "example_bzlmod",
+ "version": "0.0.0",
+ "key": "<root>",
+ "repoName": "example_bzlmod",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@rules_python//python/extensions:python.bzl",
+ "extensionName": "python",
+ "usingModule": "<root>",
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 16,
+ "column": 23
+ },
+ "imports": {
+ "python_3_10": "python_3_10",
+ "python_3_9": "python_3_9",
+ "python_versions": "python_versions"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "toolchain",
+ "attributeValues": {
+ "configure_coverage_tool": true,
+ "is_default": true,
+ "python_version": "3.9"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 17,
+ "column": 17
+ }
+ },
+ {
+ "tagName": "toolchain",
+ "attributeValues": {
+ "configure_coverage_tool": true,
+ "python_version": "3.10"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 29,
+ "column": 17
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@rules_python//python/extensions:pip.bzl",
+ "extensionName": "pip",
+ "usingModule": "<root>",
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 47,
+ "column": 20
+ },
+ "imports": {
+ "whl_mods_hub": "whl_mods_hub",
+ "pip": "pip"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "whl_mods",
+ "attributeValues": {
+ "additive_build_content_file": "//whl_mods:appended_build_content.BUILD",
+ "data": [
+ ":generated_file"
+ ],
+ "hub_name": "whl_mods_hub",
+ "whl_name": "requests"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 50,
+ "column": 13
+ }
+ },
+ {
+ "tagName": "whl_mods",
+ "attributeValues": {
+ "additive_build_content": "load(\"@bazel_skylib//rules:write_file.bzl\", \"write_file\")\nwrite_file(\n name = \"generated_file\",\n out = \"generated_file.txt\",\n content = [\"Hello world from build content file\"],\n)\n",
+ "copy_executables": {
+ "'@@//whl_mods:data/copy_executable.py'": "copied_content/executable.py"
+ },
+ "copy_files": {
+ "'@@//whl_mods:data/copy_file.txt'": "copied_content/file.txt"
+ },
+ "data": [
+ ":generated_file"
+ ],
+ "data_exclude_glob": [
+ "site-packages/*.dist-info/WHEEL"
+ ],
+ "hub_name": "whl_mods_hub",
+ "whl_name": "wheel"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 69,
+ "column": 13
+ }
+ },
+ {
+ "tagName": "parse",
+ "attributeValues": {
+ "hub_name": "pip",
+ "python_version": "3.9",
+ "requirements_lock": "//:requirements_lock_3_9.txt",
+ "requirements_windows": "//:requirements_windows_3_9.txt",
+ "whl_modifications": {
+ "@whl_mods_hub//:requests.json": "requests",
+ "@whl_mods_hub//:wheel.json": "wheel"
+ }
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 90,
+ "column": 10
+ }
+ },
+ {
+ "tagName": "parse",
+ "attributeValues": {
+ "hub_name": "pip",
+ "python_version": "3.10",
+ "requirements_lock": "//:requirements_lock_3_10.txt",
+ "requirements_windows": "//:requirements_windows_3_10.txt",
+ "whl_modifications": {
+ "@whl_mods_hub//:requests.json": "requests",
+ "@whl_mods_hub//:wheel.json": "wheel"
+ }
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@//:MODULE.bazel",
+ "line": 103,
+ "column": 10
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "rules_python": "rules_python@_",
+ "our_other_module": "other_module@_",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ }
+ },
+ "bazel_skylib@1.4.1": {
+ "name": "bazel_skylib",
+ "version": "1.4.1",
+ "key": "bazel_skylib@1.4.1",
+ "repoName": "bazel_skylib",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [
+ "//toolchains/unittest:cmd_toolchain",
+ "//toolchains/unittest:bash_toolchain"
+ ],
+ "extensionUsages": [],
+ "deps": {
+ "platforms": "platforms@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "bazel_skylib~1.4.1",
+ "urls": [
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz"
+ ],
+ "integrity": "sha256-uKFSeQF3QYCvx5iusoxGNL3M8ZxNmOe90c550f6aqtc=",
+ "strip_prefix": "",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "rules_python@_": {
+ "name": "rules_python",
+ "version": "0.0.0",
+ "key": "rules_python@_",
+ "repoName": "rules_python",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [
+ "@pythons_hub//:all"
+ ],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@rules_python//python/extensions/private:internal_deps.bzl",
+ "extensionName": "internal_deps",
+ "usingModule": "rules_python@_",
+ "location": {
+ "file": "@@rules_python~override//:MODULE.bazel",
+ "line": 15,
+ "column": 30
+ },
+ "imports": {
+ "rules_python_internal": "rules_python_internal",
+ "pypi__build": "pypi__build",
+ "pypi__click": "pypi__click",
+ "pypi__colorama": "pypi__colorama",
+ "pypi__importlib_metadata": "pypi__importlib_metadata",
+ "pypi__installer": "pypi__installer",
+ "pypi__more_itertools": "pypi__more_itertools",
+ "pypi__packaging": "pypi__packaging",
+ "pypi__pep517": "pypi__pep517",
+ "pypi__pip": "pypi__pip",
+ "pypi__pip_tools": "pypi__pip_tools",
+ "pypi__pyproject_hooks": "pypi__pyproject_hooks",
+ "pypi__setuptools": "pypi__setuptools",
+ "pypi__tomli": "pypi__tomli",
+ "pypi__wheel": "pypi__wheel",
+ "pypi__zipp": "pypi__zipp"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "install",
+ "attributeValues": {},
+ "devDependency": false,
+ "location": {
+ "file": "@@rules_python~override//:MODULE.bazel",
+ "line": 16,
+ "column": 22
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@rules_python//python/extensions:python.bzl",
+ "extensionName": "python",
+ "usingModule": "rules_python@_",
+ "location": {
+ "file": "@@rules_python~override//:MODULE.bazel",
+ "line": 41,
+ "column": 23
+ },
+ "imports": {
+ "pythons_hub": "pythons_hub"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "toolchain",
+ "attributeValues": {
+ "is_default": true,
+ "python_version": "3.11"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@rules_python~override//:MODULE.bazel",
+ "line": 47,
+ "column": 17
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "bazel_features": "bazel_features@1.1.0",
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "platforms": "platforms@0.0.7",
+ "rules_proto": "rules_proto@5.3.0-21.7",
+ "com_google_protobuf": "protobuf@21.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ }
+ },
+ "other_module@_": {
+ "name": "other_module",
+ "version": "",
+ "key": "other_module@_",
+ "repoName": "other_module",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@rules_python//python/extensions:python.bzl",
+ "extensionName": "python",
+ "usingModule": "other_module@_",
+ "location": {
+ "file": "@@other_module~override//:MODULE.bazel",
+ "line": 27,
+ "column": 23
+ },
+ "imports": {
+ "python_versions": "python_versions",
+ "python_3_9": "python_3_9",
+ "python_3_11": "python_3_11"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "toolchain",
+ "attributeValues": {
+ "configure_coverage_tool": true,
+ "python_version": "3.9"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@other_module~override//:MODULE.bazel",
+ "line": 28,
+ "column": 17
+ }
+ },
+ {
+ "tagName": "toolchain",
+ "attributeValues": {
+ "configure_coverage_tool": true,
+ "is_default": true,
+ "python_version": "3.11"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@other_module~override//:MODULE.bazel",
+ "line": 32,
+ "column": 17
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@rules_python//python/extensions:pip.bzl",
+ "extensionName": "pip",
+ "usingModule": "other_module@_",
+ "location": {
+ "file": "@@other_module~override//:MODULE.bazel",
+ "line": 47,
+ "column": 20
+ },
+ "imports": {
+ "other_module_pip": "other_module_pip"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "parse",
+ "attributeValues": {
+ "hub_name": "other_module_pip",
+ "python_version": "3.11",
+ "requirements_lock": ":requirements_lock_3_11.txt"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "@@other_module~override//:MODULE.bazel",
+ "line": 48,
+ "column": 10
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "rules_python": "rules_python@_",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ }
+ },
+ "bazel_tools@_": {
+ "name": "bazel_tools",
+ "version": "",
+ "key": "bazel_tools@_",
+ "repoName": "bazel_tools",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [
+ "@local_config_cc_toolchains//:all",
+ "@local_config_sh//:local_sh_toolchain"
+ ],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl",
+ "extensionName": "cc_configure_extension",
+ "usingModule": "bazel_tools@_",
+ "location": {
+ "file": "@@bazel_tools//:MODULE.bazel",
+ "line": 17,
+ "column": 29
+ },
+ "imports": {
+ "local_config_cc": "local_config_cc",
+ "local_config_cc_toolchains": "local_config_cc_toolchains"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl",
+ "extensionName": "xcode_configure_extension",
+ "usingModule": "bazel_tools@_",
+ "location": {
+ "file": "@@bazel_tools//:MODULE.bazel",
+ "line": 21,
+ "column": 32
+ },
+ "imports": {
+ "local_config_xcode": "local_config_xcode"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@rules_java//java:extensions.bzl",
+ "extensionName": "toolchains",
+ "usingModule": "bazel_tools@_",
+ "location": {
+ "file": "@@bazel_tools//:MODULE.bazel",
+ "line": 24,
+ "column": 32
+ },
+ "imports": {
+ "local_jdk": "local_jdk",
+ "remote_java_tools": "remote_java_tools",
+ "remote_java_tools_linux": "remote_java_tools_linux",
+ "remote_java_tools_windows": "remote_java_tools_windows",
+ "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64",
+ "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl",
+ "extensionName": "sh_configure_extension",
+ "usingModule": "bazel_tools@_",
+ "location": {
+ "file": "@@bazel_tools//:MODULE.bazel",
+ "line": 35,
+ "column": 39
+ },
+ "imports": {
+ "local_config_sh": "local_config_sh"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl",
+ "extensionName": "remote_coverage_tools_extension",
+ "usingModule": "bazel_tools@_",
+ "location": {
+ "file": "@@bazel_tools//:MODULE.bazel",
+ "line": 39,
+ "column": 48
+ },
+ "imports": {
+ "remote_coverage_tools": "remote_coverage_tools"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl",
+ "extensionName": "remote_android_tools_extensions",
+ "usingModule": "bazel_tools@_",
+ "location": {
+ "file": "@@bazel_tools//:MODULE.bazel",
+ "line": 42,
+ "column": 42
+ },
+ "imports": {
+ "android_gmaven_r8": "android_gmaven_r8",
+ "android_tools": "android_tools"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "rules_cc": "rules_cc@0.0.9",
+ "rules_java": "rules_java@7.1.0",
+ "rules_license": "rules_license@0.0.7",
+ "rules_proto": "rules_proto@5.3.0-21.7",
+ "rules_python": "rules_python@_",
+ "platforms": "platforms@0.0.7",
+ "com_google_protobuf": "protobuf@21.7",
+ "zlib": "zlib@1.3",
+ "build_bazel_apple_support": "apple_support@1.5.0",
+ "local_config_platform": "local_config_platform@_"
+ }
+ },
+ "local_config_platform@_": {
+ "name": "local_config_platform",
+ "version": "",
+ "key": "local_config_platform@_",
+ "repoName": "local_config_platform",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "platforms": "platforms@0.0.7",
+ "bazel_tools": "bazel_tools@_"
+ }
+ },
+ "platforms@0.0.7": {
+ "name": "platforms",
+ "version": "0.0.7",
+ "key": "platforms@0.0.7",
+ "repoName": "platforms",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "rules_license": "rules_license@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "platforms",
+ "urls": [
+ "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz"
+ ],
+ "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=",
+ "strip_prefix": "",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "bazel_features@1.1.0": {
+ "name": "bazel_features",
+ "version": "1.1.0",
+ "key": "bazel_features@1.1.0",
+ "repoName": "bazel_features",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@bazel_features//private:extensions.bzl",
+ "extensionName": "version_extension",
+ "usingModule": "bazel_features@1.1.0",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel",
+ "line": 6,
+ "column": 24
+ },
+ "imports": {
+ "bazel_features_globals": "bazel_features_globals",
+ "bazel_features_version": "bazel_features_version"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "bazel_features~1.1.0",
+ "urls": [
+ "https://github.com/bazel-contrib/bazel_features/releases/download/v1.1.0/bazel_features-v1.1.0.tar.gz"
+ ],
+ "integrity": "sha256-4hD6q1dkP7Z1Lwt/DRIJdqKZ1dqe0g4gEp7hE0o8/Hw=",
+ "strip_prefix": "bazel_features-1.1.0",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/bazel_features/1.1.0/patches/module_dot_bazel_version.patch": "sha256-o16WYfVZruIX5FGE8sATXKb9PLRpH26dbAVdbKPKVRk="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "rules_proto@5.3.0-21.7": {
+ "name": "rules_proto",
+ "version": "5.3.0-21.7",
+ "key": "rules_proto@5.3.0-21.7",
+ "repoName": "rules_proto",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "com_google_protobuf": "protobuf@21.7",
+ "rules_cc": "rules_cc@0.0.9",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_proto~5.3.0-21.7",
+ "urls": [
+ "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz"
+ ],
+ "integrity": "sha256-3D+yBqLLNEG0heseQjFlsjEjWh6psDG0Qzz3vB+kYN0=",
+ "strip_prefix": "rules_proto-5.3.0-21.7",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "protobuf@21.7": {
+ "name": "protobuf",
+ "version": "21.7",
+ "key": "protobuf@21.7",
+ "repoName": "protobuf",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@rules_jvm_external//:extensions.bzl",
+ "extensionName": "maven",
+ "usingModule": "protobuf@21.7",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel",
+ "line": 22,
+ "column": 22
+ },
+ "imports": {
+ "maven": "maven"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "install",
+ "attributeValues": {
+ "name": "maven",
+ "artifacts": [
+ "com.google.code.findbugs:jsr305:3.0.2",
+ "com.google.code.gson:gson:2.8.9",
+ "com.google.errorprone:error_prone_annotations:2.3.2",
+ "com.google.j2objc:j2objc-annotations:1.3",
+ "com.google.guava:guava:31.1-jre",
+ "com.google.guava:guava-testlib:31.1-jre",
+ "com.google.truth:truth:1.1.2",
+ "junit:junit:4.13.2",
+ "org.mockito:mockito-core:4.3.1"
+ ]
+ },
+ "devDependency": false,
+ "location": {
+ "file": "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel",
+ "line": 24,
+ "column": 14
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "rules_python": "rules_python@_",
+ "rules_cc": "rules_cc@0.0.9",
+ "rules_proto": "rules_proto@5.3.0-21.7",
+ "rules_java": "rules_java@7.1.0",
+ "rules_pkg": "rules_pkg@0.7.0",
+ "com_google_abseil": "abseil-cpp@20211102.0",
+ "zlib": "zlib@1.3",
+ "upb": "upb@0.0.0-20220923-a547704",
+ "rules_jvm_external": "rules_jvm_external@4.4.2",
+ "com_google_googletest": "googletest@1.11.0",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "protobuf~21.7",
+ "urls": [
+ "https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-all-21.7.zip"
+ ],
+ "integrity": "sha256-VJOiH17T/FAuZv7GuUScBqVRztYwAvpIkDxA36jeeko=",
+ "strip_prefix": "protobuf-21.7",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_module_dot_bazel.patch": "sha256-q3V2+eq0v2XF0z8z+V+QF4cynD6JvHI1y3kI/+rzl5s=",
+ "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_module_dot_bazel_for_examples.patch": "sha256-O7YP6s3lo/1opUiO0jqXYORNHdZ/2q3hjz1QGy8QdIU=",
+ "https://bcr.bazel.build/modules/protobuf/21.7/patches/relative_repo_names.patch": "sha256-RK9RjW8T5UJNG7flIrnFiNE9vKwWB+8uWWtJqXYT0w4=",
+ "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_missing_files.patch": "sha256-Hyne4DG2u5bXcWHNxNMirA2QFAe/2Cl8oMm1XJdkQIY="
+ },
+ "remote_patch_strip": 1
+ }
+ }
+ },
+ "rules_cc@0.0.9": {
+ "name": "rules_cc",
+ "version": "0.0.9",
+ "key": "rules_cc@0.0.9",
+ "repoName": "rules_cc",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [
+ "@local_config_cc_toolchains//:all"
+ ],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl",
+ "extensionName": "cc_configure_extension",
+ "usingModule": "rules_cc@0.0.9",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel",
+ "line": 9,
+ "column": 29
+ },
+ "imports": {
+ "local_config_cc_toolchains": "local_config_cc_toolchains"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "platforms": "platforms@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_cc~0.0.9",
+ "urls": [
+ "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz"
+ ],
+ "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=",
+ "strip_prefix": "rules_cc-0.0.9",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "rules_java@7.1.0": {
+ "name": "rules_java",
+ "version": "7.1.0",
+ "key": "rules_java@7.1.0",
+ "repoName": "rules_java",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [
+ "//toolchains:all",
+ "@local_jdk//:runtime_toolchain_definition",
+ "@local_jdk//:bootstrap_runtime_toolchain_definition",
+ "@remotejdk11_linux_toolchain_config_repo//:all",
+ "@remotejdk11_linux_aarch64_toolchain_config_repo//:all",
+ "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all",
+ "@remotejdk11_linux_s390x_toolchain_config_repo//:all",
+ "@remotejdk11_macos_toolchain_config_repo//:all",
+ "@remotejdk11_macos_aarch64_toolchain_config_repo//:all",
+ "@remotejdk11_win_toolchain_config_repo//:all",
+ "@remotejdk11_win_arm64_toolchain_config_repo//:all",
+ "@remotejdk17_linux_toolchain_config_repo//:all",
+ "@remotejdk17_linux_aarch64_toolchain_config_repo//:all",
+ "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all",
+ "@remotejdk17_linux_s390x_toolchain_config_repo//:all",
+ "@remotejdk17_macos_toolchain_config_repo//:all",
+ "@remotejdk17_macos_aarch64_toolchain_config_repo//:all",
+ "@remotejdk17_win_toolchain_config_repo//:all",
+ "@remotejdk17_win_arm64_toolchain_config_repo//:all",
+ "@remotejdk21_linux_toolchain_config_repo//:all",
+ "@remotejdk21_linux_aarch64_toolchain_config_repo//:all",
+ "@remotejdk21_macos_toolchain_config_repo//:all",
+ "@remotejdk21_macos_aarch64_toolchain_config_repo//:all",
+ "@remotejdk21_win_toolchain_config_repo//:all"
+ ],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@rules_java//java:extensions.bzl",
+ "extensionName": "toolchains",
+ "usingModule": "rules_java@7.1.0",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel",
+ "line": 19,
+ "column": 27
+ },
+ "imports": {
+ "remote_java_tools": "remote_java_tools",
+ "remote_java_tools_linux": "remote_java_tools_linux",
+ "remote_java_tools_windows": "remote_java_tools_windows",
+ "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64",
+ "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64",
+ "local_jdk": "local_jdk",
+ "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo",
+ "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo",
+ "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo",
+ "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo",
+ "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo",
+ "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo",
+ "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo",
+ "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo",
+ "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo",
+ "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo",
+ "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo",
+ "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo",
+ "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo",
+ "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo",
+ "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo",
+ "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo",
+ "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo",
+ "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo",
+ "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo",
+ "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo",
+ "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "platforms": "platforms@0.0.7",
+ "rules_cc": "rules_cc@0.0.9",
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "rules_proto": "rules_proto@5.3.0-21.7",
+ "rules_license": "rules_license@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0",
+ "urls": [
+ "https://github.com/bazelbuild/rules_java/releases/download/7.1.0/rules_java-7.1.0.tar.gz"
+ ],
+ "integrity": "sha256-o3pOX2OrgnFuXdau75iO2EYcegC46TYnImKJn1h81OE=",
+ "strip_prefix": "",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "rules_license@0.0.7": {
+ "name": "rules_license",
+ "version": "0.0.7",
+ "key": "rules_license@0.0.7",
+ "repoName": "rules_license",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_license~0.0.7",
+ "urls": [
+ "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz"
+ ],
+ "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=",
+ "strip_prefix": "",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "zlib@1.3": {
+ "name": "zlib",
+ "version": "1.3",
+ "key": "zlib@1.3",
+ "repoName": "zlib",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "platforms": "platforms@0.0.7",
+ "rules_cc": "rules_cc@0.0.9",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "zlib~1.3",
+ "urls": [
+ "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz"
+ ],
+ "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=",
+ "strip_prefix": "zlib-1.3",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=",
+ "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "apple_support@1.5.0": {
+ "name": "apple_support",
+ "version": "1.5.0",
+ "key": "apple_support@1.5.0",
+ "repoName": "build_bazel_apple_support",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [
+ "@local_config_apple_cc_toolchains//:all"
+ ],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl",
+ "extensionName": "apple_cc_configure_extension",
+ "usingModule": "apple_support@1.5.0",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel",
+ "line": 17,
+ "column": 35
+ },
+ "imports": {
+ "local_config_apple_cc": "local_config_apple_cc",
+ "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "platforms": "platforms@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "apple_support~1.5.0",
+ "urls": [
+ "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz"
+ ],
+ "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=",
+ "strip_prefix": "",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "rules_pkg@0.7.0": {
+ "name": "rules_pkg",
+ "version": "0.7.0",
+ "key": "rules_pkg@0.7.0",
+ "repoName": "rules_pkg",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "rules_python": "rules_python@_",
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "rules_license": "rules_license@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_pkg~0.7.0",
+ "urls": [
+ "https://github.com/bazelbuild/rules_pkg/releases/download/0.7.0/rules_pkg-0.7.0.tar.gz"
+ ],
+ "integrity": "sha256-iimOgydi7aGDBZfWT+fbWBeKqEzVkm121bdE1lWJQcI=",
+ "strip_prefix": "",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/rules_pkg/0.7.0/patches/module_dot_bazel.patch": "sha256-4OaEPZwYF6iC71ZTDg6MJ7LLqX7ZA0/kK4mT+4xKqiE="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "abseil-cpp@20211102.0": {
+ "name": "abseil-cpp",
+ "version": "20211102.0",
+ "key": "abseil-cpp@20211102.0",
+ "repoName": "abseil-cpp",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "rules_cc": "rules_cc@0.0.9",
+ "platforms": "platforms@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "abseil-cpp~20211102.0",
+ "urls": [
+ "https://github.com/abseil/abseil-cpp/archive/refs/tags/20211102.0.tar.gz"
+ ],
+ "integrity": "sha256-3PcbnLqNwMqZQMSzFqDHlr6Pq0KwcLtrfKtitI8OZsQ=",
+ "strip_prefix": "abseil-cpp-20211102.0",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/patches/module_dot_bazel.patch": "sha256-4izqopgGCey4jVZzl/w3M2GVPNohjh2B5TmbThZNvPY="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "upb@0.0.0-20220923-a547704": {
+ "name": "upb",
+ "version": "0.0.0-20220923-a547704",
+ "key": "upb@0.0.0-20220923-a547704",
+ "repoName": "upb",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "rules_proto": "rules_proto@5.3.0-21.7",
+ "com_google_protobuf": "protobuf@21.7",
+ "com_google_absl": "abseil-cpp@20211102.0",
+ "platforms": "platforms@0.0.7",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "upb~0.0.0-20220923-a547704",
+ "urls": [
+ "https://github.com/protocolbuffers/upb/archive/a5477045acaa34586420942098f5fecd3570f577.tar.gz"
+ ],
+ "integrity": "sha256-z39x6v+QskwaKLSWRan/A6mmwecTQpHOcJActj5zZLU=",
+ "strip_prefix": "upb-a5477045acaa34586420942098f5fecd3570f577",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/patches/module_dot_bazel.patch": "sha256-wH4mNS6ZYy+8uC0HoAft/c7SDsq2Kxf+J8dUakXhaB0="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "rules_jvm_external@4.4.2": {
+ "name": "rules_jvm_external",
+ "version": "4.4.2",
+ "key": "rules_jvm_external@4.4.2",
+ "repoName": "rules_jvm_external",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [
+ {
+ "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl",
+ "extensionName": "non_module_deps",
+ "usingModule": "rules_jvm_external@4.4.2",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel",
+ "line": 9,
+ "column": 32
+ },
+ "imports": {
+ "io_bazel_rules_kotlin": "io_bazel_rules_kotlin"
+ },
+ "devImports": [],
+ "tags": [],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ },
+ {
+ "extensionBzlFile": ":extensions.bzl",
+ "extensionName": "maven",
+ "usingModule": "rules_jvm_external@4.4.2",
+ "location": {
+ "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel",
+ "line": 16,
+ "column": 22
+ },
+ "imports": {
+ "rules_jvm_external_deps": "rules_jvm_external_deps"
+ },
+ "devImports": [],
+ "tags": [
+ {
+ "tagName": "install",
+ "attributeValues": {
+ "name": "rules_jvm_external_deps",
+ "artifacts": [
+ "com.google.cloud:google-cloud-core:1.93.10",
+ "com.google.cloud:google-cloud-storage:1.113.4",
+ "com.google.code.gson:gson:2.9.0",
+ "org.apache.maven:maven-artifact:3.8.6",
+ "software.amazon.awssdk:s3:2.17.183"
+ ],
+ "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json"
+ },
+ "devDependency": false,
+ "location": {
+ "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel",
+ "line": 18,
+ "column": 14
+ }
+ }
+ ],
+ "hasDevUseExtension": false,
+ "hasNonDevUseExtension": true
+ }
+ ],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "io_bazel_stardoc": "stardoc@0.5.1",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_jvm_external~4.4.2",
+ "urls": [
+ "https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/4.4.2.zip"
+ ],
+ "integrity": "sha256-c1YC9QgT6y6pPKP15DsZWb2AshO4NqB6YqKddXZwt3s=",
+ "strip_prefix": "rules_jvm_external-4.4.2",
+ "remote_patches": {},
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "googletest@1.11.0": {
+ "name": "googletest",
+ "version": "1.11.0",
+ "key": "googletest@1.11.0",
+ "repoName": "googletest",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "com_google_absl": "abseil-cpp@20211102.0",
+ "platforms": "platforms@0.0.7",
+ "rules_cc": "rules_cc@0.0.9",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "googletest~1.11.0",
+ "urls": [
+ "https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz"
+ ],
+ "integrity": "sha256-tIcL8SH/d5W6INILzdhie44Ijy0dqymaAxwQNO3ck9U=",
+ "strip_prefix": "googletest-release-1.11.0",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/googletest/1.11.0/patches/module_dot_bazel.patch": "sha256-HuahEdI/n8KCI071sN3CEziX+7qP/Ec77IWayYunLP0="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ },
+ "stardoc@0.5.1": {
+ "name": "stardoc",
+ "version": "0.5.1",
+ "key": "stardoc@0.5.1",
+ "repoName": "stardoc",
+ "executionPlatformsToRegister": [],
+ "toolchainsToRegister": [],
+ "extensionUsages": [],
+ "deps": {
+ "bazel_skylib": "bazel_skylib@1.4.1",
+ "rules_java": "rules_java@7.1.0",
+ "bazel_tools": "bazel_tools@_",
+ "local_config_platform": "local_config_platform@_"
+ },
+ "repoSpec": {
+ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "stardoc~0.5.1",
+ "urls": [
+ "https://github.com/bazelbuild/stardoc/releases/download/0.5.1/stardoc-0.5.1.tar.gz"
+ ],
+ "integrity": "sha256-qoFNrgrEALurLoiB+ZFcb0fElmS/CHxAmhX5BDjSwj4=",
+ "strip_prefix": "",
+ "remote_patches": {
+ "https://bcr.bazel.build/modules/stardoc/0.5.1/patches/module_dot_bazel.patch": "sha256-UAULCuTpJE7SG0YrR9XLjMfxMRmbP+za3uW9ONZ5rjI="
+ },
+ "remote_patch_strip": 0
+ }
+ }
+ }
+ },
+ "moduleExtensions": {
+ "@@apple_support~1.5.0//crosstool:setup.bzl%apple_cc_configure_extension": {
+ "general": {
+ "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "local_config_apple_cc": {
+ "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl",
+ "ruleClassName": "_apple_cc_autoconf",
+ "attributes": {
+ "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc"
+ }
+ },
+ "local_config_apple_cc_toolchains": {
+ "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl",
+ "ruleClassName": "_apple_cc_autoconf_toolchains",
+ "attributes": {
+ "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains"
+ }
+ }
+ }
+ }
+ },
+ "@@bazel_features~1.1.0//private:extensions.bzl%version_extension": {
+ "general": {
+ "bzlTransitiveDigest": "LKmXjK1avT44pRhO3x6Hplu1mU9qrNOaHP+/tJ0VFfE=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "bazel_features_version": {
+ "bzlFile": "@@bazel_features~1.1.0//private:version_repo.bzl",
+ "ruleClassName": "version_repo",
+ "attributes": {
+ "name": "bazel_features~1.1.0~version_extension~bazel_features_version"
+ }
+ },
+ "bazel_features_globals": {
+ "bzlFile": "@@bazel_features~1.1.0//private:globals_repo.bzl",
+ "ruleClassName": "globals_repo",
+ "attributes": {
+ "name": "bazel_features~1.1.0~version_extension~bazel_features_globals",
+ "globals": {
+ "RunEnvironmentInfo": "5.3.0",
+ "DefaultInfo": "0.0.1",
+ "__TestingOnly_NeverAvailable": "1000000000.0.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": {
+ "general": {
+ "bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "local_config_cc": {
+ "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl",
+ "ruleClassName": "cc_autoconf",
+ "attributes": {
+ "name": "bazel_tools~cc_configure_extension~local_config_cc"
+ }
+ },
+ "local_config_cc_toolchains": {
+ "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl",
+ "ruleClassName": "cc_autoconf_toolchains",
+ "attributes": {
+ "name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains"
+ }
+ }
+ }
+ }
+ },
+ "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": {
+ "general": {
+ "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "local_config_xcode": {
+ "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl",
+ "ruleClassName": "xcode_autoconf",
+ "attributes": {
+ "name": "bazel_tools~xcode_configure_extension~local_config_xcode",
+ "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m",
+ "remote_xcode": ""
+ }
+ }
+ }
+ }
+ },
+ "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": {
+ "general": {
+ "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "local_config_sh": {
+ "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl",
+ "ruleClassName": "sh_config",
+ "attributes": {
+ "name": "bazel_tools~sh_configure_extension~local_config_sh"
+ }
+ }
+ }
+ }
+ },
+ "@@rules_java~7.1.0//java:extensions.bzl%toolchains": {
+ "general": {
+ "bzlTransitiveDigest": "iUIRqCK7tkhvcDJCAfPPqSd06IHG0a8HQD0xeQyVAqw=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "remotejdk21_linux_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_linux_s390x_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_macos_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk21_macos_aarch64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_linux_aarch64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk21_macos_aarch64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n",
+ "sha256": "2a7a99a3ea263dbd8d32a67d1e6e363ba8b25c645c826f5e167a02bbafaff1fa",
+ "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk17_linux_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_macos_aarch64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca",
+ "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz"
+ ]
+ }
+ },
+ "remote_java_tools_windows": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remote_java_tools_windows",
+ "sha256": "c5c70c214a350f12cbf52da8270fa43ba629b795f3dd328028a38f8f0d39c2a1",
+ "urls": [
+ "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_windows-v13.1.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_windows-v13.1.zip"
+ ]
+ }
+ },
+ "remotejdk11_win": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_win",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83",
+ "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip",
+ "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip"
+ ]
+ }
+ },
+ "remotejdk11_win_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_win_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_linux_aarch64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de",
+ "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk17_linux": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340",
+ "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk11_linux_s390x_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_linux_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_macos": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_macos",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd",
+ "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk11_win_arm64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2",
+ "strip_prefix": "jdk-11.0.13+8",
+ "urls": [
+ "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip"
+ ]
+ }
+ },
+ "remotejdk17_macos": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_macos",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f",
+ "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk21_macos": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_macos",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n",
+ "sha256": "9639b87db586d0c89f7a9892ae47f421e442c64b97baebdff31788fbe23265bd",
+ "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk21_macos_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_macos_aarch64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_win": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_win",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637",
+ "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip",
+ "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip"
+ ]
+ }
+ },
+ "remotejdk11_macos_aarch64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_linux_ppc64le_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk21_linux": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_linux",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n",
+ "sha256": "0c0eadfbdc47a7ca64aeab51b9c061f71b6e4d25d2d87674512e9b6387e9e3a6",
+ "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz"
+ ]
+ }
+ },
+ "remote_java_tools_linux": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remote_java_tools_linux",
+ "sha256": "d134da9b04c9023fb6e56a5d4bffccee73f7bc9572ddc4e747778dacccd7a5a7",
+ "urls": [
+ "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_linux-v13.1.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_linux-v13.1.zip"
+ ]
+ }
+ },
+ "remotejdk21_win": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_win",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n",
+ "sha256": "e9959d500a0d9a7694ac243baf657761479da132f0f94720cbffd092150bd802",
+ "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-win_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip",
+ "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip"
+ ]
+ }
+ },
+ "remotejdk21_linux_aarch64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n",
+ "sha256": "1fb64b8036c5d463d8ab59af06bf5b6b006811e6012e3b0eb6bccf57f1c55835",
+ "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk11_linux_aarch64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_linux_s390x": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b",
+ "strip_prefix": "jdk-11.0.15+10",
+ "urls": [
+ "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz",
+ "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz"
+ ]
+ }
+ },
+ "remotejdk17_linux_aarch64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313",
+ "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk17_win_arm64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_linux": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c",
+ "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk11_macos_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_linux_ppc64le_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk17_win_arm64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85",
+ "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip",
+ "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip"
+ ]
+ }
+ },
+ "remote_java_tools_darwin_arm64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_arm64",
+ "sha256": "dab5bb87ec43e980faea6e1cec14bafb217b8e2f5346f53aa784fd715929a930",
+ "urls": [
+ "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_arm64-v13.1.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_arm64-v13.1.zip"
+ ]
+ }
+ },
+ "remotejdk17_linux_ppc64le": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd",
+ "strip_prefix": "jdk-17.0.8.1+1",
+ "urls": [
+ "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz",
+ "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz"
+ ]
+ }
+ },
+ "remotejdk21_linux_aarch64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_win_arm64_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n"
+ }
+ },
+ "local_jdk": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:local_java_repository.bzl",
+ "ruleClassName": "_local_java_repository_rule",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~local_jdk",
+ "java_home": "",
+ "version": "",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n"
+ }
+ },
+ "remote_java_tools_darwin_x86_64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_x86_64",
+ "sha256": "0db40d8505a2b65ef0ed46e4256757807db8162f7acff16225be57c1d5726dbc",
+ "urls": [
+ "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_x86_64-v13.1.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_x86_64-v13.1.zip"
+ ]
+ }
+ },
+ "remote_java_tools": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remote_java_tools",
+ "sha256": "286bdbbd66e616fc4ed3f90101418729a73baa7e8c23a98ffbef558f74c0ad14",
+ "urls": [
+ "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools-v13.1.zip",
+ "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools-v13.1.zip"
+ ]
+ }
+ },
+ "remotejdk17_linux_s390x": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n",
+ "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37",
+ "strip_prefix": "jdk-17.0.8.1+1",
+ "urls": [
+ "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz",
+ "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz"
+ ]
+ }
+ },
+ "remotejdk17_win_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk17_win_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n"
+ }
+ },
+ "remotejdk11_linux_ppc64le": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f",
+ "strip_prefix": "jdk-11.0.15+10",
+ "urls": [
+ "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz",
+ "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz"
+ ]
+ }
+ },
+ "remotejdk11_macos_aarch64": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64",
+ "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n",
+ "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885",
+ "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64",
+ "urls": [
+ "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz",
+ "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz"
+ ]
+ }
+ },
+ "remotejdk21_win_toolchain_config_repo": {
+ "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl",
+ "ruleClassName": "_toolchain_config",
+ "attributes": {
+ "name": "rules_java~7.1.0~toolchains~remotejdk21_win_toolchain_config_repo",
+ "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n"
+ }
+ }
+ }
+ }
+ },
+ "@@rules_python~override//python/extensions:pip.bzl%pip": {
+ "os:linux,arch:amd64": {
+ "bzlTransitiveDigest": "1T9ZEQ+rBH1TjZEfm65J0aKyfLCqdjxklv9pEmkBMRM=",
+ "accumulatedFileDigests": {
+ "@@//:requirements_lock_3_10.txt": "8a691c254cde6884cef3fd9f75479cc10118b6886f6ba44721501f37e1266c1c",
+ "@@//whl_mods:appended_build_content.BUILD": "275102ec5574229531650038302ac51025d72e7f7a5c65c01cf33a96d1e646dd",
+ "@@other_module~override//:requirements_lock_3_11.txt": "a7d0061366569043d5efcf80e34a32c732679367cb3c831c4cdc606adc36d314",
+ "@@//:requirements_lock_3_9.txt": "a47c1883329eb4505e1a986252ee5d3be7da0c315462442f42fec381b5dda2be"
+ },
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "pip_39_tomli": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_tomli",
+ "requirement": "tomli==2.0.1 --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_lazy_object_proxy": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_lazy_object_proxy",
+ "requirement": "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",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_typing_extensions": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_typing_extensions",
+ "requirement": "typing-extensions==4.6.3 --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_idna": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_idna",
+ "requirement": "idna==2.10 --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_isort": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_isort",
+ "requirement": "isort==5.12.0 --hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 --hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_astroid": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_astroid",
+ "requirement": "astroid==2.13.5 --hash=sha256:6891f444625b6edb2ac798829b689e95297e100ddf89dbed5a8c610e34901501 --hash=sha256:df164d5ac811b9f44105a72b8f9d5edfb7b5b2d7e979b04ea377a77b3229114a",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_tabulate": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_tabulate",
+ "requirement": "tabulate==0.9.0 --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_wrapt": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_wrapt",
+ "requirement": "wrapt==1.15.0 --hash=sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0 --hash=sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420 --hash=sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a --hash=sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c --hash=sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079 --hash=sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923 --hash=sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f --hash=sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1 --hash=sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8 --hash=sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86 --hash=sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0 --hash=sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364 --hash=sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e --hash=sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c --hash=sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e --hash=sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c --hash=sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727 --hash=sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff --hash=sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e --hash=sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29 --hash=sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7 --hash=sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72 --hash=sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475 --hash=sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a --hash=sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317 --hash=sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2 --hash=sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd --hash=sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640 --hash=sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98 --hash=sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248 --hash=sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e --hash=sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d --hash=sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec --hash=sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1 --hash=sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e --hash=sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9 --hash=sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92 --hash=sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb --hash=sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094 --hash=sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46 --hash=sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29 --hash=sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd --hash=sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705 --hash=sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8 --hash=sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975 --hash=sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb --hash=sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e --hash=sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b --hash=sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418 --hash=sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019 --hash=sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1 --hash=sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba --hash=sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6 --hash=sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2 --hash=sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3 --hash=sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7 --hash=sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752 --hash=sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416 --hash=sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f --hash=sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1 --hash=sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc --hash=sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145 --hash=sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee --hash=sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a --hash=sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7 --hash=sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b --hash=sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653 --hash=sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0 --hash=sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90 --hash=sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29 --hash=sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6 --hash=sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034 --hash=sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09 --hash=sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559 --hash=sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "pip_hub_repository_bzlmod",
+ "attributes": {
+ "name": "rules_python~override~pip~pip",
+ "repo_name": "pip",
+ "whl_map": {
+ "astroid": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "certifi": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "chardet": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "dill": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "idna": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "isort": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "lazy_object_proxy": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "mccabe": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "pathspec": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "platformdirs": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "pylint": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "pylint_print": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "python_dateutil": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "python_magic": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "pyyaml": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "requests": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "s3cmd": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "six": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "tabulate": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "tomli": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "tomlkit": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "typing_extensions": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "urllib3": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "websockets": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "wheel": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "wrapt": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "yamllint": [
+ "3.9.18",
+ "3.10.13"
+ ],
+ "setuptools": [
+ "3.9.18"
+ ]
+ },
+ "default_version": "3.9.18"
+ }
+ },
+ "pip_39_websockets": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_websockets",
+ "requirement": "websockets==11.0.3 --hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd --hash=sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f --hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 --hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 --hash=sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788 --hash=sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa --hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f --hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 --hash=sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7 --hash=sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f --hash=sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd --hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 --hash=sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb --hash=sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b --hash=sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016 --hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac --hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 --hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb --hash=sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99 --hash=sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e --hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 --hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf --hash=sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007 --hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 --hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 --hash=sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86 --hash=sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1 --hash=sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61 --hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 --hash=sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8 --hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f --hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 --hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 --hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 --hash=sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae --hash=sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd --hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b --hash=sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311 --hash=sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af --hash=sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152 --hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 --hash=sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de --hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 --hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d --hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d --hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca --hash=sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0 --hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 --hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b --hash=sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e --hash=sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128 --hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d --hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c --hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 --hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 --hash=sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b --hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b --hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 --hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c --hash=sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c --hash=sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f --hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 --hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 --hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb --hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 --hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf --hash=sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0 --hash=sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74 --hash=sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0 --hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_chardet": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_chardet",
+ "requirement": "chardet==4.0.0 --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_s3cmd": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_s3cmd",
+ "requirement": "s3cmd==2.1.0 --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_python_dateutil": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_python_dateutil",
+ "requirement": "python-dateutil==2.8.2 --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_requests": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_requests",
+ "requirement": "requests==2.25.1 --hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 --hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "annotation": "@@rules_python~override~pip~whl_mods_hub//:requests.json",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_tomli": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_tomli",
+ "requirement": "tomli==2.0.1 --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_setuptools": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_setuptools",
+ "requirement": "setuptools==65.6.3 --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_idna": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_idna",
+ "requirement": "idna==2.10 --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_python_dateutil": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_python_dateutil",
+ "requirement": "python-dateutil==2.8.2 --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_typing_extensions": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_typing_extensions",
+ "requirement": "typing-extensions==4.4.0 --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_python_magic": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_python_magic",
+ "requirement": "python-magic==0.4.27 --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_tomlkit": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_tomlkit",
+ "requirement": "tomlkit==0.11.6 --hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b --hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_platformdirs": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_platformdirs",
+ "requirement": "platformdirs==3.5.1 --hash=sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f --hash=sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_pylint_print": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_pylint_print",
+ "requirement": "pylint-print==1.0.1 --hash=sha256:30aa207e9718ebf4ceb47fb87012092e6d8743aab932aa07aa14a73e750ad3d0 --hash=sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_astroid": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_astroid",
+ "requirement": "astroid==2.12.13 --hash=sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907 --hash=sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_pyyaml": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_pyyaml",
+ "requirement": "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",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_tabulate": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_tabulate",
+ "requirement": "tabulate==0.9.0 --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_dill": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_dill",
+ "requirement": "dill==0.3.6 --hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 --hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_lazy_object_proxy": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_lazy_object_proxy",
+ "requirement": "lazy-object-proxy==1.9.0 --hash=sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382 --hash=sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82 --hash=sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9 --hash=sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494 --hash=sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46 --hash=sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30 --hash=sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63 --hash=sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4 --hash=sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae --hash=sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be --hash=sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701 --hash=sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd --hash=sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006 --hash=sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a --hash=sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586 --hash=sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8 --hash=sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821 --hash=sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07 --hash=sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b --hash=sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171 --hash=sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b --hash=sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2 --hash=sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7 --hash=sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4 --hash=sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8 --hash=sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e --hash=sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f --hash=sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda --hash=sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4 --hash=sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e --hash=sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671 --hash=sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11 --hash=sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455 --hash=sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734 --hash=sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb --hash=sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_pylint": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_pylint",
+ "requirement": "pylint==2.15.10 --hash=sha256:9df0d07e8948a1c3ffa3b6e2d7e6e63d9fb457c5da5b961ed63106594780cc7e --hash=sha256:b3dc5ef7d33858f297ac0d06cc73862f01e4f2e74025ec3eff347ce0bc60baf5",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_urllib3": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_urllib3",
+ "requirement": "urllib3==1.26.13 --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_certifi": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_certifi",
+ "requirement": "certifi==2022.12.7 --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_tomlkit": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_tomlkit",
+ "requirement": "tomlkit==0.11.8 --hash=sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171 --hash=sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "other_module_pip_311_absl_py": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~other_module_pip_311_absl_py",
+ "requirement": "absl-py==1.4.0 --hash=sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47 --hash=sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d",
+ "repo": "other_module_pip_311",
+ "repo_prefix": "other_module_pip_311_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_11_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_yamllint": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_yamllint",
+ "requirement": "yamllint==1.32.0 --hash=sha256:d01dde008c65de5b235188ab3110bebc59d18e5c65fc8a58267cd211cd9df34a --hash=sha256:d97a66e48da820829d96077d76b8dfbe6c6140f106e558dae87e81ac4e6b30b7",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_requests": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_requests",
+ "requirement": "requests==2.25.1 --hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 --hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "annotation": "@@rules_python~override~pip~whl_mods_hub//:requests.json",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "other_module_pip": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "pip_hub_repository_bzlmod",
+ "attributes": {
+ "name": "rules_python~override~pip~other_module_pip",
+ "repo_name": "other_module_pip",
+ "whl_map": {
+ "absl_py": [
+ "3.11.6"
+ ]
+ },
+ "default_version": "3.9.18"
+ }
+ },
+ "pip_39_six": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_six",
+ "requirement": "six==1.16.0 --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_mccabe": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_mccabe",
+ "requirement": "mccabe==0.7.0 --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_pylint_print": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_pylint_print",
+ "requirement": "pylint-print==1.0.1 --hash=sha256:30aa207e9718ebf4ceb47fb87012092e6d8743aab932aa07aa14a73e750ad3d0 --hash=sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_python_magic": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_python_magic",
+ "requirement": "python-magic==0.4.27 --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_isort": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_isort",
+ "requirement": "isort==5.11.4 --hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 --hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_pathspec": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_pathspec",
+ "requirement": "pathspec==0.10.3 --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "whl_mods_hub": {
+ "bzlFile": "@@rules_python~override//python/extensions:pip.bzl",
+ "ruleClassName": "_whl_mods_repo",
+ "attributes": {
+ "name": "rules_python~override~pip~whl_mods_hub",
+ "whl_mods": {
+ "requests": "{\"additive_build_content\":\"load(\\\"@bazel_skylib//rules:write_file.bzl\\\", \\\"write_file\\\")\\n\\nwrite_file(\\n name = \\\"generated_file\\\",\\n out = \\\"generated_file.txt\\\",\\n content = [\\\"Hello world from requests\\\"],\\n)\\n\",\"copy_executables\":{},\"copy_files\":{},\"data\":[\":generated_file\"],\"data_exclude_glob\":[],\"srcs_exclude_glob\":[]}",
+ "wheel": "{\"additive_build_content\":\"load(\\\"@bazel_skylib//rules:write_file.bzl\\\", \\\"write_file\\\")\\nwrite_file(\\n name = \\\"generated_file\\\",\\n out = \\\"generated_file.txt\\\",\\n content = [\\\"Hello world from build content file\\\"],\\n)\\n\",\"copy_executables\":{\"@@//whl_mods:data/copy_executable.py\":\"copied_content/executable.py\"},\"copy_files\":{\"@@//whl_mods:data/copy_file.txt\":\"copied_content/file.txt\"},\"data\":[\":generated_file\"],\"data_exclude_glob\":[\"site-packages/*.dist-info/WHEEL\"],\"srcs_exclude_glob\":[]}"
+ }
+ }
+ },
+ "pip_39_mccabe": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_mccabe",
+ "requirement": "mccabe==0.7.0 --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_platformdirs": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_platformdirs",
+ "requirement": "platformdirs==2.6.0 --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_certifi": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_certifi",
+ "requirement": "certifi==2023.5.7 --hash=sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7 --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_pyyaml": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_pyyaml",
+ "requirement": "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",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_yamllint": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_yamllint",
+ "requirement": "yamllint==1.28.0 --hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 --hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_s3cmd": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_s3cmd",
+ "requirement": "s3cmd==2.1.0 --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_chardet": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_chardet",
+ "requirement": "chardet==4.0.0 --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_dill": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_dill",
+ "requirement": "dill==0.3.6 --hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 --hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_wheel": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_wheel",
+ "requirement": "wheel==0.40.0 --hash=sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873 --hash=sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "annotation": "@@rules_python~override~pip~whl_mods_hub//:wheel.json",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_pylint": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_pylint",
+ "requirement": "pylint==2.15.9 --hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 --hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_39_wrapt": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_39_wrapt",
+ "requirement": "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",
+ "repo": "pip_39",
+ "repo_prefix": "pip_39_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_urllib3": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_urllib3",
+ "requirement": "urllib3==1.26.16 --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_six": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_six",
+ "requirement": "six==1.16.0 --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_pathspec": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_pathspec",
+ "requirement": "pathspec==0.11.1 --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_wheel": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_wheel",
+ "requirement": "wheel==0.40.0 --hash=sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873 --hash=sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "annotation": "@@rules_python~override~pip~whl_mods_hub//:wheel.json",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ },
+ "pip_310_websockets": {
+ "bzlFile": "@@rules_python~override//python/pip_install:pip_repository.bzl",
+ "ruleClassName": "whl_library",
+ "attributes": {
+ "name": "rules_python~override~pip~pip_310_websockets",
+ "requirement": "websockets==11.0.3 --hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd --hash=sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f --hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 --hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 --hash=sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788 --hash=sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa --hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f --hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 --hash=sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7 --hash=sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f --hash=sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd --hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 --hash=sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb --hash=sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b --hash=sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016 --hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac --hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 --hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb --hash=sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99 --hash=sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e --hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 --hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf --hash=sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007 --hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 --hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 --hash=sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86 --hash=sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1 --hash=sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61 --hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 --hash=sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8 --hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f --hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 --hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 --hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 --hash=sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae --hash=sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd --hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b --hash=sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311 --hash=sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af --hash=sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152 --hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 --hash=sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de --hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 --hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d --hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d --hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca --hash=sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0 --hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 --hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b --hash=sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e --hash=sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128 --hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d --hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c --hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 --hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 --hash=sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b --hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b --hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 --hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c --hash=sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c --hash=sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f --hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 --hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 --hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb --hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 --hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf --hash=sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0 --hash=sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74 --hash=sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0 --hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564",
+ "repo": "pip_310",
+ "repo_prefix": "pip_310_",
+ "python_interpreter": "",
+ "python_interpreter_target": "@@rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu//:bin/python3",
+ "quiet": true,
+ "timeout": 600,
+ "isolated": true,
+ "extra_pip_args": [
+ "--extra-index-url",
+ "https://pypi.python.org/simple/"
+ ],
+ "download_only": false,
+ "pip_data_exclude": [],
+ "enable_implicit_namespace_pkgs": false,
+ "environment": {}
+ }
+ }
+ }
+ }
+ },
+ "@@rules_python~override//python/extensions:python.bzl%python": {
+ "general": {
+ "bzlTransitiveDigest": "um1PsPhf8NOD6Qkf5ix7Gf2asyhE3Fl6J5gEfPfNz/s=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "python_3_11_s390x-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_s390x-unknown-linux-gnu",
+ "sha256": "f9f19823dba3209cedc4647b00f46ed0177242917db20fb7fb539970e384531c",
+ "patches": [],
+ "platform": "s390x-unknown-linux-gnu",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-s390x-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-s390x-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_aarch64-apple-darwin": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_aarch64-apple-darwin",
+ "sha256": "fd027b1dedf1ea034cdaa272e91771bdf75ddef4c8653b05d224a0645aa2ca3c",
+ "patches": [],
+ "platform": "aarch64-apple-darwin",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_10_aarch64-apple-darwin_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_x86_64-apple-darwin": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_x86_64-apple-darwin",
+ "sha256": "be0b19b6af1f7d8c667e5abef5505ad06cf72e5a11bb5844970c395a7e5b1275",
+ "patches": [],
+ "platform": "x86_64-apple-darwin",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_10_x86_64-apple-darwin_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_11_aarch64-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_aarch64-unknown-linux-gnu",
+ "sha256": "3e26a672df17708c4dc928475a5974c3fb3a34a9b45c65fb4bd1e50504cc84ec",
+ "patches": [],
+ "platform": "aarch64-unknown-linux-gnu",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_ppc64le-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_ppc64le-unknown-linux-gnu",
+ "sha256": "f3f9c43eec1a0c3f72845d0b705da17a336d3906b7df212d2640b8f47e8ff375",
+ "patches": [],
+ "platform": "ppc64le-unknown-linux-gnu",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_x86_64-pc-windows-msvc": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_x86_64-pc-windows-msvc",
+ "sha256": "b8d930ce0d04bda83037ad3653d7450f8907c88e24bb8255a29b8dab8930d6f1",
+ "patches": [],
+ "platform": "x86_64-pc-windows-msvc",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "pythons_hub": {
+ "bzlFile": "@@rules_python~override//python/extensions/private:pythons_hub.bzl",
+ "ruleClassName": "hub_repo",
+ "attributes": {
+ "name": "rules_python~override~python~pythons_hub",
+ "default_python_version": "3.9",
+ "toolchain_prefixes": [
+ "_0000_python_3_10_",
+ "_0001_python_3_11_",
+ "_0002_python_3_9_"
+ ],
+ "toolchain_python_versions": [
+ "3.10",
+ "3.11",
+ "3.9"
+ ],
+ "toolchain_set_python_version_constraints": [
+ "True",
+ "True",
+ "False"
+ ],
+ "toolchain_user_repository_names": [
+ "python_3_10",
+ "python_3_11",
+ "python_3_9"
+ ]
+ }
+ },
+ "python_3_10_x86_64-apple-darwin_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_x86_64-apple-darwin_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_10_x86_64-apple-darwin//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/01/24/be01e62a7bce89bcffe04729c540382caa5a06bee45ae42136c93e2499f5/coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl"
+ ]
+ }
+ },
+ "python_3_9_ppc64le-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_ppc64le-unknown-linux-gnu",
+ "sha256": "101c38b22fb2f5a0945156da4259c8e9efa0c08de9d7f59afa51e7ce6e22a1cc",
+ "patches": [],
+ "platform": "ppc64le-unknown-linux-gnu",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_11_ppc64le-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_ppc64le-unknown-linux-gnu",
+ "sha256": "7937035f690a624dba4d014ffd20c342e843dd46f89b0b0a1e5726b85deb8eaf",
+ "patches": [],
+ "platform": "ppc64le-unknown-linux-gnu",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_9_x86_64-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu",
+ "sha256": "f3ff38b1ccae7dcebd8bbf2e533c9a984fac881de0ffd1636fbb61842bd924de",
+ "patches": [],
+ "platform": "x86_64-unknown-linux-gnu",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_9_x86_64-unknown-linux-gnu_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_9_s390x-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_s390x-unknown-linux-gnu",
+ "sha256": "eee31e55ffbc1f460d7b17f05dd89e45a2636f374a6f8dc29ea13d0497f7f586",
+ "patches": [],
+ "platform": "s390x-unknown-linux-gnu",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-s390x-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-s390x-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_9_x86_64-unknown-linux-gnu_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_x86_64-unknown-linux-gnu_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_9_x86_64-unknown-linux-gnu//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/fe/57/e4f8ad64d84ca9e759d783a052795f62a9f9111585e46068845b1cb52c2b/coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
+ ]
+ }
+ },
+ "python_3_9_aarch64-unknown-linux-gnu_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_aarch64-unknown-linux-gnu_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_9_aarch64-unknown-linux-gnu//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/61/af/5964b8d7d9a5c767785644d9a5a63cacba9a9c45cc42ba06d25895ec87be/coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
+ ]
+ }
+ },
+ "python_3_9": {
+ "bzlFile": "@@rules_python~override//python/private:toolchains_repo.bzl",
+ "ruleClassName": "toolchain_aliases",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9",
+ "python_version": "3.9.18",
+ "user_repository_name": "python_3_9"
+ }
+ },
+ "python_3_11_aarch64-apple-darwin": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_aarch64-apple-darwin",
+ "sha256": "916c35125b5d8323a21526d7a9154ca626453f63d0878e95b9f613a95006c990",
+ "patches": [],
+ "platform": "aarch64-apple-darwin",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-aarch64-apple-darwin-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-aarch64-apple-darwin-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_11_x86_64-pc-windows-msvc": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_x86_64-pc-windows-msvc",
+ "sha256": "3933545e6d41462dd6a47e44133ea40995bc6efeed8c2e4cbdf1a699303e95ea",
+ "patches": [],
+ "platform": "x86_64-pc-windows-msvc",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_9_aarch64-apple-darwin_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_aarch64-apple-darwin_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_9_aarch64-apple-darwin//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/ca/0c/3dfeeb1006c44b911ee0ed915350db30325d01808525ae7cc8d57643a2ce/coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl"
+ ]
+ }
+ },
+ "python_3_9_aarch64-apple-darwin": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_aarch64-apple-darwin",
+ "sha256": "fdc4054837e37b69798c2ef796222a480bc1f80e8ad3a01a95d0168d8282a007",
+ "patches": [],
+ "platform": "aarch64-apple-darwin",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-aarch64-apple-darwin-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-aarch64-apple-darwin-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_9_aarch64-apple-darwin_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_aarch64-apple-darwin_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_aarch64-apple-darwin_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_10_aarch64-apple-darwin//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/3d/80/7060a445e1d2c9744b683dc935248613355657809d6c6b2716cdf4ca4766/coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl"
+ ]
+ }
+ },
+ "python_3_10_aarch64-unknown-linux-gnu_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_aarch64-unknown-linux-gnu_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_10_aarch64-unknown-linux-gnu//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/b8/9d/926fce7e03dbfc653104c2d981c0fa71f0572a9ebd344d24c573bd6f7c4f/coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
+ ]
+ }
+ },
+ "python_3_9_x86_64-apple-darwin_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_x86_64-apple-darwin_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_9_x86_64-apple-darwin//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/88/da/495944ebf0ad246235a6bd523810d9f81981f9b81c6059ba1f56e943abe0/coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl"
+ ]
+ }
+ },
+ "python_3_9_x86_64-pc-windows-msvc": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_x86_64-pc-windows-msvc",
+ "sha256": "02ea7bb64524886bd2b05d6b6be4401035e4ba4319146f274f0bcd992822cd75",
+ "patches": [],
+ "platform": "x86_64-pc-windows-msvc",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_9_aarch64-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_aarch64-unknown-linux-gnu",
+ "sha256": "1e0a3e8ce8e58901a259748c0ab640d2b8294713782d14229e882c6898b2fb36",
+ "patches": [],
+ "platform": "aarch64-unknown-linux-gnu",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_9_aarch64-unknown-linux-gnu_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_aarch64-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_aarch64-unknown-linux-gnu",
+ "sha256": "8675915ff454ed2f1597e27794bc7df44f5933c26b94aa06af510fe91b58bb97",
+ "patches": [],
+ "platform": "aarch64-unknown-linux-gnu",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_10_aarch64-unknown-linux-gnu_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_x86_64-unknown-linux-gnu_coverage": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu_coverage",
+ "build_file_content": "\nfilegroup(\n name = \"coverage\",\n srcs = [\"coverage/__main__.py\"],\n data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n visibility = [\"@python_3_10_x86_64-unknown-linux-gnu//:__subpackages__\"],\n)\n ",
+ "patch_args": [
+ "-p1"
+ ],
+ "patches": [
+ "@@rules_python~override//python/private:coverage.patch"
+ ],
+ "sha256": "31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063",
+ "type": "zip",
+ "urls": [
+ "https://files.pythonhosted.org/packages/b4/bd/1b2331e3a04f4cc9b7b332b1dd0f3a1261dfc4114f8479bebfcc2afee9e8/coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
+ ]
+ }
+ },
+ "python_3_11": {
+ "bzlFile": "@@rules_python~override//python/private:toolchains_repo.bzl",
+ "ruleClassName": "toolchain_aliases",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11",
+ "python_version": "3.11.6",
+ "user_repository_name": "python_3_11"
+ }
+ },
+ "python_3_10_s390x-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_s390x-unknown-linux-gnu",
+ "sha256": "859f6cfe9aedb6e8858892fdc124037e83ab05f28d42a7acd314c6a16d6bd66c",
+ "patches": [],
+ "platform": "s390x-unknown-linux-gnu",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10": {
+ "bzlFile": "@@rules_python~override//python/private:toolchains_repo.bzl",
+ "ruleClassName": "toolchain_aliases",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10",
+ "python_version": "3.10.13",
+ "user_repository_name": "python_3_10"
+ }
+ },
+ "python_3_11_x86_64-apple-darwin": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_x86_64-apple-darwin",
+ "sha256": "178cb1716c2abc25cb56ae915096c1a083e60abeba57af001996e8bc6ce1a371",
+ "patches": [],
+ "platform": "x86_64-apple-darwin",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-x86_64-apple-darwin-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-x86_64-apple-darwin-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_versions": {
+ "bzlFile": "@@rules_python~override//python/private:toolchains_repo.bzl",
+ "ruleClassName": "multi_toolchain_aliases",
+ "attributes": {
+ "name": "rules_python~override~python~python_versions",
+ "python_versions": {
+ "3.9": "python_3_9",
+ "3.10": "python_3_10",
+ "3.11": "python_3_11"
+ }
+ }
+ },
+ "python_3_9_x86_64-apple-darwin": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_9_x86_64-apple-darwin",
+ "sha256": "82231cb77d4a5c8081a1a1d5b8ae440abe6993514eb77a926c826e9a69a94fb1",
+ "patches": [],
+ "platform": "x86_64-apple-darwin",
+ "python_version": "3.9.18",
+ "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-apple-darwin-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-apple-darwin-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_9_x86_64-apple-darwin_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_10_x86_64-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_10_x86_64-unknown-linux-gnu",
+ "sha256": "5d0429c67c992da19ba3eb58b3acd0b35ec5e915b8cae9a4aa8ca565c423847a",
+ "patches": [],
+ "platform": "x86_64-unknown-linux-gnu",
+ "python_version": "3.10.13",
+ "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "@python_3_10_x86_64-unknown-linux-gnu_coverage//:coverage",
+ "ignore_root_user_error": false
+ }
+ },
+ "python_3_11_x86_64-unknown-linux-gnu": {
+ "bzlFile": "@@rules_python~override//python:repositories.bzl",
+ "ruleClassName": "python_repository",
+ "attributes": {
+ "name": "rules_python~override~python~python_3_11_x86_64-unknown-linux-gnu",
+ "sha256": "ee37a7eae6e80148c7e3abc56e48a397c1664f044920463ad0df0fc706eacea8",
+ "patches": [],
+ "platform": "x86_64-unknown-linux-gnu",
+ "python_version": "3.11.6",
+ "release_filename": "20231002/cpython-3.11.6+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz",
+ "urls": [
+ "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.11.6+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz"
+ ],
+ "distutils_content": "",
+ "strip_prefix": "python",
+ "coverage_tool": "",
+ "ignore_root_user_error": false
+ }
+ }
+ }
+ }
+ },
+ "@@rules_python~override//python/extensions/private:internal_deps.bzl%internal_deps": {
+ "general": {
+ "bzlTransitiveDigest": "xWcXgf89ru5MrJTsPvm77jragVvWzXfqANqHTd0qAEw=",
+ "accumulatedFileDigests": {},
+ "envVariables": {},
+ "generatedRepoSpecs": {
+ "pypi__wheel": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__wheel",
+ "url": "https://files.pythonhosted.org/packages/b8/8b/31273bf66016be6ad22bb7345c37ff350276cfd46e389a0c2ac5da9d9073/wheel-0.41.2-py3-none-any.whl",
+ "sha256": "75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__click": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__click",
+ "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
+ "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__importlib_metadata": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__importlib_metadata",
+ "url": "https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl",
+ "sha256": "3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__pyproject_hooks": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__pyproject_hooks",
+ "url": "https://files.pythonhosted.org/packages/d5/ea/9ae603de7fbb3df820b23a70f6aff92bf8c7770043254ad8d2dc9d6bcba4/pyproject_hooks-1.0.0-py3-none-any.whl",
+ "sha256": "283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__pep517": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__pep517",
+ "url": "https://files.pythonhosted.org/packages/ee/2f/ef63e64e9429111e73d3d6cbee80591672d16f2725e648ebc52096f3d323/pep517-0.13.0-py3-none-any.whl",
+ "sha256": "4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__packaging": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__packaging",
+ "url": "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl",
+ "sha256": "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__pip_tools": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__pip_tools",
+ "url": "https://files.pythonhosted.org/packages/e8/df/47e6267c6b5cdae867adbdd84b437393e6202ce4322de0a5e0b92960e1d6/pip_tools-7.3.0-py3-none-any.whl",
+ "sha256": "8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__setuptools": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__setuptools",
+ "url": "https://files.pythonhosted.org/packages/4f/ab/0bcfebdfc3bfa8554b2b2c97a555569c4c1ebc74ea288741ea8326c51906/setuptools-68.1.2-py3-none-any.whl",
+ "sha256": "3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__zipp": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__zipp",
+ "url": "https://files.pythonhosted.org/packages/8c/08/d3006317aefe25ea79d3b76c9650afabaf6d63d1c8443b236e7405447503/zipp-3.16.2-py3-none-any.whl",
+ "sha256": "679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__colorama": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__colorama",
+ "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
+ "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__build": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__build",
+ "url": "https://files.pythonhosted.org/packages/58/91/17b00d5fac63d3dca605f1b8269ba3c65e98059e1fd99d00283e42a454f0/build-0.10.0-py3-none-any.whl",
+ "sha256": "af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "rules_python_internal": {
+ "bzlFile": "@@rules_python~override//python/private:internal_config_repo.bzl",
+ "ruleClassName": "internal_config_repo",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~rules_python_internal"
+ }
+ },
+ "pypi__pip": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__pip",
+ "url": "https://files.pythonhosted.org/packages/50/c2/e06851e8cc28dcad7c155f4753da8833ac06a5c704c109313b8d5a62968a/pip-23.2.1-py3-none-any.whl",
+ "sha256": "7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__installer": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__installer",
+ "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
+ "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__more_itertools": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__more_itertools",
+ "url": "https://files.pythonhosted.org/packages/5a/cb/6dce742ea14e47d6f565589e859ad225f2a5de576d7696e0623b784e226b/more_itertools-10.1.0-py3-none-any.whl",
+ "sha256": "64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ },
+ "pypi__tomli": {
+ "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+ "ruleClassName": "http_archive",
+ "attributes": {
+ "name": "rules_python~override~internal_deps~pypi__tomli",
+ "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
+ "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
+ "type": "zip",
+ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/bzlmod/entry_point/BUILD.bazel b/examples/bzlmod/entry_point/BUILD.bazel
deleted file mode 100644
index f68552c..0000000
--- a/examples/bzlmod/entry_point/BUILD.bazel
+++ /dev/null
@@ -1,20 +0,0 @@
-load("@pip_39//: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_points/BUILD.bazel b/examples/bzlmod/entry_points/BUILD.bazel
new file mode 100644
index 0000000..a0939cb
--- /dev/null
+++ b/examples/bzlmod/entry_points/BUILD.bazel
@@ -0,0 +1,33 @@
+load("@python_versions//3.9:defs.bzl", py_console_script_binary_3_9 = "py_console_script_binary")
+load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
+
+# This is how you can define a `pylint` entrypoint which uses the default python version.
+py_console_script_binary(
+ name = "pylint",
+ pkg = "@pip//pylint",
+ visibility = ["//entry_points:__subpackages__"],
+)
+
+# We can also specify extra dependencies for the binary, which is useful for
+# tools like flake8, pylint, pytest, which have plugin discovery methods.
+py_console_script_binary(
+ name = "pylint_with_deps",
+ pkg = "@pip//pylint",
+ # Because `pylint` has multiple console_scripts available, we have to
+ # specify which we want if the name of the target name 'pylint_with_deps'
+ # cannot be used to guess the entry_point script.
+ script = "pylint",
+ visibility = ["//entry_points:__subpackages__"],
+ deps = [
+ # One can add extra dependencies to the entry point.
+ "@pip//pylint_print",
+ ],
+)
+
+# A specific Python version can be forced by using the generated version-aware
+# wrappers, e.g. to force Python 3.9:
+py_console_script_binary_3_9(
+ name = "yamllint",
+ pkg = "@pip//yamllint:pkg",
+ visibility = ["//entry_points:__subpackages__"],
+)
diff --git a/examples/bzlmod/entry_points/tests/BUILD.bazel b/examples/bzlmod/entry_points/tests/BUILD.bazel
new file mode 100644
index 0000000..5a65e9e
--- /dev/null
+++ b/examples/bzlmod/entry_points/tests/BUILD.bazel
@@ -0,0 +1,63 @@
+load("@bazel_skylib//rules:run_binary.bzl", "run_binary")
+load("@rules_python//python:defs.bzl", "py_test")
+
+# Below are targets for testing the `py_console_script_binary` feature and are
+# not part of the example how to use the feature.
+
+# And a test that we can correctly run `pylint --version`
+py_test(
+ name = "pylint_test",
+ srcs = ["pylint_test.py"],
+ data = ["//entry_points:pylint"],
+ env = {
+ "ENTRY_POINT": "$(rlocationpath //entry_points:pylint)",
+ },
+ deps = ["@rules_python//python/runfiles"],
+)
+
+# Next run pylint on the file to generate a report.
+run_binary(
+ name = "pylint_report",
+ srcs = [
+ ":file_with_pylint_errors.py",
+ ],
+ outs = ["pylint_report.txt"],
+ args = [
+ "--output-format=text:$(location pylint_report.txt)",
+ "--load-plugins=pylint_print",
+ # The `exit-zero` ensures that `run_binary` is successful even though there are lint errors.
+ # We check the generated report in the test below.
+ "--exit-zero",
+ "$(location :file_with_pylint_errors.py)",
+ ],
+ env = {
+ # otherwise it may try to create ${HOME}/.cache/pylint
+ "PYLINTHOME": "./.pylint_home",
+ },
+ tool = "//entry_points:pylint_with_deps",
+)
+
+py_test(
+ name = "pylint_deps_test",
+ srcs = ["pylint_deps_test.py"],
+ data = [
+ ":pylint_report",
+ "//entry_points:pylint_with_deps",
+ ],
+ env = {
+ "ENTRY_POINT": "$(rlocationpath //entry_points:pylint_with_deps)",
+ "PYLINT_REPORT": "$(rlocationpath :pylint_report)",
+ },
+ deps = ["@rules_python//python/runfiles"],
+)
+
+# And a test to check that yamllint works
+py_test(
+ name = "yamllint_test",
+ srcs = ["yamllint_test.py"],
+ data = ["//entry_points:yamllint"],
+ env = {
+ "ENTRY_POINT": "$(rlocationpath //entry_points:yamllint)",
+ },
+ deps = ["@rules_python//python/runfiles"],
+)
diff --git a/examples/bzlmod/entry_points/tests/file_with_pylint_errors.py b/examples/bzlmod/entry_points/tests/file_with_pylint_errors.py
new file mode 100644
index 0000000..bb3dbab
--- /dev/null
+++ b/examples/bzlmod/entry_points/tests/file_with_pylint_errors.py
@@ -0,0 +1,6 @@
+"""
+A file to demonstrate the pylint-print checker works.
+"""
+
+if __name__ == "__main__":
+ print("Hello, World!")
diff --git a/examples/bzlmod/entry_points/tests/pylint_deps_test.py b/examples/bzlmod/entry_points/tests/pylint_deps_test.py
new file mode 100644
index 0000000..f6743ce
--- /dev/null
+++ b/examples/bzlmod/entry_points/tests/pylint_deps_test.py
@@ -0,0 +1,72 @@
+# 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 tempfile
+import unittest
+
+from python.runfiles import runfiles
+
+
+class ExampleTest(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ self.maxDiff = None
+
+ super().__init__(*args, **kwargs)
+
+ def test_pylint_entry_point(self):
+ rlocation_path = os.environ.get("ENTRY_POINT")
+ assert (
+ rlocation_path is not None
+ ), "expected '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")
+
+ # Let's run the entrypoint and check the tool version.
+ #
+ # NOTE @aignas 2023-08-24: the Windows python launcher with Python 3.9 and bazel 6 is not happy if we start
+ # passing extra files via `subprocess.run` and it starts to fail with an error that the file which is the
+ # entry_point cannot be found. However, just calling `--version` seems to be fine.
+ proc = subprocess.run(
+ [str(entry_point), "--version"],
+ check=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ self.assertEqual(
+ "",
+ proc.stderr.decode("utf-8").strip(),
+ )
+ self.assertRegex(proc.stdout.decode("utf-8").strip(), "^pylint 2\.15\.9")
+
+ def test_pylint_report_has_expected_warnings(self):
+ rlocation_path = os.environ.get("PYLINT_REPORT")
+ assert (
+ rlocation_path is not None
+ ), "expected 'PYLINT_REPORT' env variable to be set to rlocation of the report"
+
+ pylint_report = pathlib.Path(runfiles.Create().Rlocation(rlocation_path))
+ self.assertTrue(pylint_report.exists(), f"'{pylint_report}' does not exist")
+
+ self.assertRegex(
+ pylint_report.read_text().strip(),
+ "W8201: Logging should be used instead of the print\(\) function\. \(print-function\)",
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/examples/bzlmod/entry_points/tests/pylint_test.py b/examples/bzlmod/entry_points/tests/pylint_test.py
new file mode 100644
index 0000000..c253293
--- /dev/null
+++ b/examples/bzlmod/entry_points/tests/pylint_test.py
@@ -0,0 +1,57 @@
+# 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 __init__(self, *args, **kwargs):
+ self.maxDiff = None
+
+ super().__init__(*args, **kwargs)
+
+ def test_pylint_entry_point(self):
+ rlocation_path = os.environ.get("ENTRY_POINT")
+ assert (
+ rlocation_path is not None
+ ), "expected '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")
+
+ # Let's run the entrypoint and check the tool version.
+ #
+ # NOTE @aignas 2023-08-24: the Windows python launcher with Python 3.9 and bazel 6 is not happy if we start
+ # passing extra files via `subprocess.run` and it starts to fail with an error that the file which is the
+ # entry_point cannot be found. However, just calling `--version` seems to be fine.
+ proc = subprocess.run(
+ [str(entry_point), "--version"],
+ check=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ self.assertEqual(
+ "",
+ proc.stderr.decode("utf-8").strip(),
+ )
+ self.assertRegex(proc.stdout.decode("utf-8").strip(), "^pylint 2\.15\.9")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/examples/bzlmod/entry_point/test_entry_point.py b/examples/bzlmod/entry_points/tests/yamllint_test.py
index 5a37458..0a02357 100644
--- a/examples/bzlmod/entry_point/test_entry_point.py
+++ b/examples/bzlmod/entry_points/tests/yamllint_test.py
@@ -21,15 +21,25 @@ from python.runfiles import runfiles
class ExampleTest(unittest.TestCase):
- def test_entry_point(self):
- rlocation_path = os.environ.get("YAMLLINT_ENTRY_POINT")
+ def __init__(self, *args, **kwargs):
+ self.maxDiff = None
+
+ super().__init__(*args, **kwargs)
+
+ def test_yamllint_entry_point(self):
+ rlocation_path = os.environ.get("ENTRY_POINT")
assert (
rlocation_path is not None
- ), "expected 'YAMLLINT_ENTRY_POINT' env variable to be set to rlocation of the tool"
+ ), "expected '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")
+ # Let's run the entrypoint and check the tool version.
+ #
+ # NOTE @aignas 2023-08-24: the Windows python launcher with Python 3.9 and bazel 6 is not happy if we start
+ # passing extra files via `subprocess.run` and it starts to fail with an error that the file which is the
+ # entry_point cannot be found. However, just calling `--version` seems to be fine.
proc = subprocess.run(
[str(entry_point), "--version"],
check=True,
diff --git a/examples/bzlmod/gazelle_python.yaml b/examples/bzlmod/gazelle_python.yaml
deleted file mode 100644
index 12096e5..0000000
--- a/examples/bzlmod/gazelle_python.yaml
+++ /dev/null
@@ -1,590 +0,0 @@
-# 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/lib.py b/examples/bzlmod/lib.py
index 646c6e8..5f0167f 100644
--- a/examples/bzlmod/lib.py
+++ b/examples/bzlmod/lib.py
@@ -13,7 +13,7 @@
# limitations under the License.
from tabulate import tabulate
-
+import sphinx # noqa
def main(table):
return tabulate(table)
diff --git a/examples/bzlmod/other_module/BUILD.bazel b/examples/bzlmod/other_module/BUILD.bazel
new file mode 100644
index 0000000..a93b92a
--- /dev/null
+++ b/examples/bzlmod/other_module/BUILD.bazel
@@ -0,0 +1,9 @@
+load("@python_versions//3.11:defs.bzl", compile_pip_requirements_311 = "compile_pip_requirements")
+
+# NOTE: To update the requirements, you need to uncomment the rules_python
+# override in the MODULE.bazel.
+compile_pip_requirements_311(
+ name = "requirements",
+ src = "requirements.in",
+ requirements_txt = "requirements_lock_3_11.txt",
+)
diff --git a/examples/bzlmod/other_module/MODULE.bazel b/examples/bzlmod/other_module/MODULE.bazel
index cc23a51..959501a 100644
--- a/examples/bzlmod/other_module/MODULE.bazel
+++ b/examples/bzlmod/other_module/MODULE.bazel
@@ -6,10 +6,20 @@ module(
# that the parent module uses.
bazel_dep(name = "rules_python", version = "")
-# It is not best practice to use a python.toolchian in
-# a submodule. This code only exists to test that
-# we support doing this. This code is only for rules_python
-# testing purposes.
+# The story behind this commented out override:
+# This override is necessary to generate/update the requirements file
+# for this module. This is because running it via the outer
+# module doesn't work -- the `requirements.update` target can't find
+# the correct file to update.
+# Running in the submodule itself works, but submodules using overrides
+# is considered an error until Bazel 6.3, which prevents the outer module
+# from depending on this module.
+# So until 6.3 and higher is the minimum, we leave this commented out.
+# local_path_override(
+# module_name = "rules_python",
+# path = "../../..",
+# )
+
PYTHON_NAME_39 = "python_3_9"
PYTHON_NAME_311 = "python_3_11"
@@ -29,6 +39,20 @@ python.toolchain(
# created by the above python.toolchain calls.
use_repo(
python,
+ "python_versions",
PYTHON_NAME_39,
PYTHON_NAME_311,
)
+
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+pip.parse(
+ hub_name = "other_module_pip",
+ # NOTE: This version must be different than the root module's
+ # default python version.
+ # This is testing that a sub-module can use pip.parse() and only specify
+ # Python versions that DON'T include whatever the root-module's default
+ # Python version is.
+ python_version = "3.11",
+ requirements_lock = ":requirements_lock_3_11.txt",
+)
+use_repo(pip, "other_module_pip")
diff --git a/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel b/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel
index 6e37df8..021c969 100644
--- a/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel
+++ b/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel
@@ -1,4 +1,7 @@
-load("@python_3_11//:defs.bzl", py_binary_311 = "py_binary")
+load(
+ "@python_3_11//:defs.bzl",
+ py_binary_311 = "py_binary",
+)
load("@rules_python//python:defs.bzl", "py_library")
py_library(
@@ -13,11 +16,16 @@ py_library(
# used only when you need to support multiple versions of Python
# in the same project.
py_binary_311(
- name = "lib_311",
- srcs = ["lib.py"],
+ name = "bin",
+ srcs = ["bin.py"],
data = ["data/data.txt"],
+ main = "bin.py",
visibility = ["//visibility:public"],
- deps = ["@rules_python//python/runfiles"],
+ deps = [
+ ":lib",
+ "@other_module_pip//absl_py",
+ "@rules_python//python/runfiles",
+ ],
)
exports_files(["data/data.txt"])
diff --git a/examples/bzlmod/other_module/other_module/pkg/bin.py b/examples/bzlmod/other_module/other_module/pkg/bin.py
new file mode 100644
index 0000000..3e28ca2
--- /dev/null
+++ b/examples/bzlmod/other_module/other_module/pkg/bin.py
@@ -0,0 +1,6 @@
+import sys
+
+import absl
+
+print("Python version:", sys.version)
+print("Module 'absl':", absl)
diff --git a/examples/bzlmod/other_module/requirements.in b/examples/bzlmod/other_module/requirements.in
new file mode 100644
index 0000000..b998a06
--- /dev/null
+++ b/examples/bzlmod/other_module/requirements.in
@@ -0,0 +1 @@
+absl-py
diff --git a/examples/bzlmod/other_module/requirements_lock_3_11.txt b/examples/bzlmod/other_module/requirements_lock_3_11.txt
new file mode 100644
index 0000000..7e350f2
--- /dev/null
+++ b/examples/bzlmod/other_module/requirements_lock_3_11.txt
@@ -0,0 +1,10 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+# bazel run //other_module/pkg:requirements.update
+#
+absl-py==1.4.0 \
+ --hash=sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47 \
+ --hash=sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d
+ # via -r other_module/pkg/requirements.in
diff --git a/examples/bzlmod/patches/BUILD.bazel b/examples/bzlmod/patches/BUILD.bazel
new file mode 100644
index 0000000..ed2af79
--- /dev/null
+++ b/examples/bzlmod/patches/BUILD.bazel
@@ -0,0 +1,4 @@
+exports_files(
+ srcs = glob(["*.patch"]),
+ visibility = ["//visibility:public"],
+)
diff --git a/examples/py_proto_library/WORKSPACE.bzlmod b/examples/bzlmod/patches/empty.patch
index e69de29..e69de29 100644
--- a/examples/py_proto_library/WORKSPACE.bzlmod
+++ b/examples/bzlmod/patches/empty.patch
diff --git a/examples/bzlmod/patches/requests_metadata.patch b/examples/bzlmod/patches/requests_metadata.patch
new file mode 100644
index 0000000..3a52410
--- /dev/null
+++ b/examples/bzlmod/patches/requests_metadata.patch
@@ -0,0 +1,12 @@
+diff --unified --recursive a/requests-2.25.1.dist-info/METADATA b/requests-2.25.1.dist-info/METADATA
+--- a/requests-2.25.1.dist-info/METADATA 2020-12-16 19:37:50.000000000 +0900
++++ b/requests-2.25.1.dist-info/METADATA 2023-09-30 20:31:50.079863410 +0900
+@@ -1,7 +1,7 @@
+ Metadata-Version: 2.1
+ Name: requests
+ Version: 2.25.1
+-Summary: Python HTTP for Humans.
++Summary: Python HTTP for Humans. Patched.
+ Home-page: https://requests.readthedocs.io
+ Author: Kenneth Reitz
+ Author-email: me@kennethreitz.org
diff --git a/examples/bzlmod/patches/requests_record.patch b/examples/bzlmod/patches/requests_record.patch
new file mode 100644
index 0000000..0167510
--- /dev/null
+++ b/examples/bzlmod/patches/requests_record.patch
@@ -0,0 +1,11 @@
+--- a/requests-2.25.1.dist-info/RECORD
++++ b/requests-2.25.1.dist-info/RECORD
+@@ -17,7 +17,7 @@
+ requests/structures.py,sha256=msAtr9mq1JxHd-JRyiILfdFlpbJwvvFuP3rfUQT_QxE,3005
+ requests/utils.py,sha256=_K9AgkN6efPe-a-zgZurXzds5PBC0CzDkyjAE2oCQFQ,30529
+ requests-2.25.1.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
+-requests-2.25.1.dist-info/METADATA,sha256=RuNh38uN0IMsRT3OwaTNB_WyGx6RMwwQoMwujXfkUVM,4168
++requests-2.25.1.dist-info/METADATA,sha256=fRSAA0u0Bi0heD4zYq91wdNUTJlbzhK6_iDOcRRNDx4,4177
+ requests-2.25.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110
+ requests-2.25.1.dist-info/top_level.txt,sha256=fMSVmHfb5rbGOo6xv-O_tUX6j-WyixssE-SnwcDRxNQ,9
+ requests-2.25.1.dist-info/RECORD,,
diff --git a/examples/bzlmod/py_proto_library/BUILD.bazel b/examples/bzlmod/py_proto_library/BUILD.bazel
new file mode 100644
index 0000000..d0bc683
--- /dev/null
+++ b/examples/bzlmod/py_proto_library/BUILD.bazel
@@ -0,0 +1,18 @@
+load("@rules_python//python:py_test.bzl", "py_test")
+
+py_test(
+ name = "pricetag_test",
+ srcs = ["test.py"],
+ main = "test.py",
+ deps = [
+ "//py_proto_library/example.com/proto:pricetag_proto_py_pb2",
+ ],
+)
+
+py_test(
+ name = "message_test",
+ srcs = ["message_test.py"],
+ deps = [
+ "//py_proto_library/example.com/another_proto:message_proto_py_pb2",
+ ],
+)
diff --git a/examples/bzlmod/py_proto_library/example.com/another_proto/BUILD.bazel b/examples/bzlmod/py_proto_library/example.com/another_proto/BUILD.bazel
new file mode 100644
index 0000000..806fcb9
--- /dev/null
+++ b/examples/bzlmod/py_proto_library/example.com/another_proto/BUILD.bazel
@@ -0,0 +1,16 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@rules_python//python:proto.bzl", "py_proto_library")
+
+py_proto_library(
+ name = "message_proto_py_pb2",
+ visibility = ["//visibility:public"],
+ deps = [":message_proto"],
+)
+
+proto_library(
+ name = "message_proto",
+ srcs = ["message.proto"],
+ # https://bazel.build/reference/be/protocol-buffer#proto_library.strip_import_prefix
+ strip_import_prefix = "/py_proto_library/example.com",
+ deps = ["//py_proto_library/example.com/proto:pricetag_proto"],
+)
diff --git a/examples/bzlmod/py_proto_library/example.com/another_proto/message.proto b/examples/bzlmod/py_proto_library/example.com/another_proto/message.proto
new file mode 100644
index 0000000..6e7dcc5
--- /dev/null
+++ b/examples/bzlmod/py_proto_library/example.com/another_proto/message.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+
+package rules_python;
+
+import "proto/pricetag.proto";
+
+message TestMessage {
+ uint32 index = 1;
+ PriceTag pricetag = 2;
+}
diff --git a/examples/bzlmod/py_proto_library/example.com/proto/BUILD.bazel b/examples/bzlmod/py_proto_library/example.com/proto/BUILD.bazel
new file mode 100644
index 0000000..fa20f2c
--- /dev/null
+++ b/examples/bzlmod/py_proto_library/example.com/proto/BUILD.bazel
@@ -0,0 +1,17 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@rules_python//python:proto.bzl", "py_proto_library")
+
+py_proto_library(
+ name = "pricetag_proto_py_pb2",
+ visibility = ["//visibility:public"],
+ deps = [":pricetag_proto"],
+)
+
+proto_library(
+ name = "pricetag_proto",
+ srcs = ["pricetag.proto"],
+ # https://bazel.build/reference/be/protocol-buffer#proto_library.strip_import_prefix
+ strip_import_prefix = "/py_proto_library/example.com",
+ visibility = ["//visibility:public"],
+ deps = ["@com_google_protobuf//:any_proto"],
+)
diff --git a/examples/py_proto_library/pricetag.proto b/examples/bzlmod/py_proto_library/example.com/proto/pricetag.proto
index c952248..3fa68de 100644
--- a/examples/py_proto_library/pricetag.proto
+++ b/examples/bzlmod/py_proto_library/example.com/proto/pricetag.proto
@@ -1,8 +1,11 @@
syntax = "proto3";
+import "google/protobuf/any.proto";
+
package rules_python;
message PriceTag {
string name = 2;
double cost = 1;
+ google.protobuf.Any metadata = 3;
}
diff --git a/examples/bzlmod/py_proto_library/message_test.py b/examples/bzlmod/py_proto_library/message_test.py
new file mode 100644
index 0000000..b1a6942
--- /dev/null
+++ b/examples/bzlmod/py_proto_library/message_test.py
@@ -0,0 +1,16 @@
+import sys
+import unittest
+
+from another_proto import message_pb2
+
+
+class TestCase(unittest.TestCase):
+ def test_message(self):
+ got = message_pb2.TestMessage(
+ index=5,
+ )
+ self.assertIsNotNone(got)
+
+
+if __name__ == "__main__":
+ sys.exit(unittest.main())
diff --git a/examples/bzlmod/py_proto_library/test.py b/examples/bzlmod/py_proto_library/test.py
new file mode 100644
index 0000000..24ab8dd
--- /dev/null
+++ b/examples/bzlmod/py_proto_library/test.py
@@ -0,0 +1,21 @@
+import json
+import unittest
+
+from proto import pricetag_pb2
+
+
+class TestCase(unittest.TestCase):
+ def test_pricetag(self):
+ got = pricetag_pb2.PriceTag(
+ name="dollar",
+ cost=5.00,
+ )
+
+ metadata = {"description": "some text..."}
+ got.metadata.value = json.dumps(metadata).encode("utf-8")
+
+ self.assertIsNotNone(got)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/examples/bzlmod/requirements.in b/examples/bzlmod/requirements.in
index 47cdcf1..a713577 100644
--- a/examples/bzlmod/requirements.in
+++ b/examples/bzlmod/requirements.in
@@ -1,4 +1,4 @@
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
wheel
websockets
@@ -7,4 +7,8 @@ s3cmd~=2.1.0
yamllint>=1.28.0
tabulate~=0.9.0
pylint~=2.15.5
+pylint-print
python-dateutil>=2.8.2
+sphinx
+sphinxcontrib-serializinghtml
+colorama
diff --git a/examples/bzlmod/requirements_lock_3_10.txt b/examples/bzlmod/requirements_lock_3_10.txt
index e3a185a..525fa3e 100644
--- a/examples/bzlmod/requirements_lock_3_10.txt
+++ b/examples/bzlmod/requirements_lock_3_10.txt
@@ -4,12 +4,20 @@
#
# bazel run //:requirements_3_10.update
#
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
astroid==2.13.5 \
--hash=sha256:6891f444625b6edb2ac798829b689e95297e100ddf89dbed5a8c610e34901501 \
--hash=sha256:df164d5ac811b9f44105a72b8f9d5edfb7b5b2d7e979b04ea377a77b3229114a
# via pylint
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
certifi==2023.5.7 \
--hash=sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7 \
--hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716
@@ -18,18 +26,34 @@ chardet==4.0.0 \
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
# via requests
+colorama==0.4.6 \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+ # via -r requirements.in
dill==0.3.6 \
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
# via pylint
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
idna==2.10 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
# via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
isort==5.12.0 \
--hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 \
--hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6
# via pylint
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via sphinx
lazy-object-proxy==1.9.0 \
--hash=sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382 \
--hash=sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82 \
@@ -68,10 +92,76 @@ lazy-object-proxy==1.9.0 \
--hash=sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb \
--hash=sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59
# via astroid
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
mccabe==0.7.0 \
--hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
--hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
# via pylint
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
pathspec==0.11.1 \
--hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \
--hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293
@@ -80,9 +170,19 @@ platformdirs==3.5.1 \
--hash=sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f \
--hash=sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5
# via pylint
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
pylint==2.15.10 \
--hash=sha256:9df0d07e8948a1c3ffa3b6e2d7e6e63d9fb457c5da5b961ed63106594780cc7e \
--hash=sha256:b3dc5ef7d33858f297ac0d06cc73862f01e4f2e74025ec3eff347ce0bc60baf5
+ # via
+ # -r requirements.in
+ # pylint-print
+pylint-print==1.0.1 \
+ --hash=sha256:30aa207e9718ebf4ceb47fb87012092e6d8743aab932aa07aa14a73e750ad3d0 \
+ --hash=sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b
# via -r requirements.in
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
@@ -139,7 +239,9 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r requirements.in
+ # via
+ # -r requirements.in
+ # sphinx
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
@@ -148,6 +250,46 @@ six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
# via python-dateutil
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
@@ -164,9 +306,9 @@ typing-extensions==4.6.3 \
--hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \
--hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5
# via astroid
-urllib3==1.26.16 \
- --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \
- --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
diff --git a/examples/bzlmod/requirements_lock_3_9.txt b/examples/bzlmod/requirements_lock_3_9.txt
index ba1d4d7..e78562f 100644
--- a/examples/bzlmod/requirements_lock_3_9.txt
+++ b/examples/bzlmod/requirements_lock_3_9.txt
@@ -4,12 +4,20 @@
#
# bazel run //:requirements_3_9.update
#
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
astroid==2.12.13 \
--hash=sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907 \
--hash=sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7
# via pylint
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
certifi==2022.12.7 \
--hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
--hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
@@ -18,18 +26,38 @@ chardet==4.0.0 \
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
# via requests
+colorama==0.4.6 \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+ # via -r requirements.in
dill==0.3.6 \
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
# via pylint
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
idna==2.10 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
# via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
+importlib-metadata==6.8.0 \
+ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \
+ --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743
+ # via sphinx
isort==5.11.4 \
--hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 \
--hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b
# via pylint
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via sphinx
lazy-object-proxy==1.8.0 \
--hash=sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada \
--hash=sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d \
@@ -51,10 +79,76 @@ lazy-object-proxy==1.8.0 \
--hash=sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0 \
--hash=sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b
# via astroid
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
mccabe==0.7.0 \
--hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
--hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
# via pylint
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
pathspec==0.10.3 \
--hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
--hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
@@ -63,9 +157,19 @@ platformdirs==2.6.0 \
--hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \
--hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e
# via pylint
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
pylint==2.15.9 \
--hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 \
--hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb
+ # via
+ # -r requirements.in
+ # pylint-print
+pylint-print==1.0.1 \
+ --hash=sha256:30aa207e9718ebf4ceb47fb87012092e6d8743aab932aa07aa14a73e750ad3d0 \
+ --hash=sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b
# via -r requirements.in
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
@@ -122,19 +226,57 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r requirements.in
+ # via
+ # -r requirements.in
+ # sphinx
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
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
@@ -153,9 +295,9 @@ typing-extensions==4.4.0 \
# via
# astroid
# pylint
-urllib3==1.26.13 \
- --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
- --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
@@ -303,3 +445,13 @@ yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+zipp==3.17.0 \
+ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \
+ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0
+ # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
diff --git a/examples/bzlmod/requirements_windows_3_10.txt b/examples/bzlmod/requirements_windows_3_10.txt
index 9a28ae8..05905e5 100644
--- a/examples/bzlmod/requirements_windows_3_10.txt
+++ b/examples/bzlmod/requirements_windows_3_10.txt
@@ -4,12 +4,20 @@
#
# bazel run //:requirements_3_10.update
#
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
astroid==2.13.5 \
--hash=sha256:6891f444625b6edb2ac798829b689e95297e100ddf89dbed5a8c610e34901501 \
--hash=sha256:df164d5ac811b9f44105a72b8f9d5edfb7b5b2d7e979b04ea377a77b3229114a
# via pylint
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
certifi==2023.5.7 \
--hash=sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7 \
--hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716
@@ -21,19 +29,34 @@ chardet==4.0.0 \
colorama==0.4.6 \
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
- # via pylint
+ # via
+ # -r requirements.in
+ # pylint
+ # sphinx
dill==0.3.6 \
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
# via pylint
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
idna==2.10 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
# via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
isort==5.12.0 \
--hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 \
--hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6
# via pylint
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via sphinx
lazy-object-proxy==1.9.0 \
--hash=sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382 \
--hash=sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82 \
@@ -72,10 +95,76 @@ lazy-object-proxy==1.9.0 \
--hash=sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb \
--hash=sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59
# via astroid
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
mccabe==0.7.0 \
--hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
--hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
# via pylint
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
pathspec==0.11.1 \
--hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \
--hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293
@@ -84,9 +173,19 @@ platformdirs==3.5.1 \
--hash=sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f \
--hash=sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5
# via pylint
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
pylint==2.15.10 \
--hash=sha256:9df0d07e8948a1c3ffa3b6e2d7e6e63d9fb457c5da5b961ed63106594780cc7e \
--hash=sha256:b3dc5ef7d33858f297ac0d06cc73862f01e4f2e74025ec3eff347ce0bc60baf5
+ # via
+ # -r requirements.in
+ # pylint-print
+pylint-print==1.0.1 \
+ --hash=sha256:30aa207e9718ebf4ceb47fb87012092e6d8743aab932aa07aa14a73e750ad3d0 \
+ --hash=sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b
# via -r requirements.in
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
@@ -143,7 +242,9 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r requirements.in
+ # via
+ # -r requirements.in
+ # sphinx
s3cmd==2.1.0 \
--hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
--hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
@@ -152,6 +253,46 @@ six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
# via python-dateutil
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
@@ -168,9 +309,9 @@ typing-extensions==4.6.3 \
--hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \
--hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5
# via astroid
-urllib3==1.26.16 \
- --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \
- --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
diff --git a/examples/bzlmod/requirements_windows_3_9.txt b/examples/bzlmod/requirements_windows_3_9.txt
index 08f0979..a325101 100644
--- a/examples/bzlmod/requirements_windows_3_9.txt
+++ b/examples/bzlmod/requirements_windows_3_9.txt
@@ -4,12 +4,20 @@
#
# bazel run //:requirements_3_9.update
#
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
astroid==2.12.13 \
--hash=sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907 \
--hash=sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7
# via pylint
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
certifi==2022.12.7 \
--hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
--hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
@@ -21,19 +29,38 @@ chardet==4.0.0 \
colorama==0.4.6 \
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
- # via pylint
+ # via
+ # -r requirements.in
+ # pylint
+ # sphinx
dill==0.3.6 \
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
# via pylint
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
idna==2.10 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
# via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
+importlib-metadata==6.8.0 \
+ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \
+ --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743
+ # via sphinx
isort==5.11.4 \
--hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 \
--hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b
# via pylint
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via sphinx
lazy-object-proxy==1.8.0 \
--hash=sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada \
--hash=sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d \
@@ -55,10 +82,76 @@ lazy-object-proxy==1.8.0 \
--hash=sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0 \
--hash=sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b
# via astroid
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
mccabe==0.7.0 \
--hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
--hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
# via pylint
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
pathspec==0.10.3 \
--hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
--hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
@@ -67,9 +160,19 @@ platformdirs==2.6.0 \
--hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \
--hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e
# via pylint
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
pylint==2.15.9 \
--hash=sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4 \
--hash=sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb
+ # via
+ # -r requirements.in
+ # pylint-print
+pylint-print==1.0.1 \
+ --hash=sha256:30aa207e9718ebf4ceb47fb87012092e6d8743aab932aa07aa14a73e750ad3d0 \
+ --hash=sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b
# via -r requirements.in
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
@@ -126,19 +229,57 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r requirements.in
+ # via
+ # -r requirements.in
+ # sphinx
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
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
tabulate==0.9.0 \
--hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
--hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
@@ -157,9 +298,9 @@ typing-extensions==4.4.0 \
# via
# astroid
# pylint
-urllib3==1.26.13 \
- --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
- --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
@@ -307,3 +448,13 @@ yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+zipp==3.17.0 \
+ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \
+ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0
+ # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
diff --git a/examples/bzlmod/test.py b/examples/bzlmod/test.py
index 80cd027..5331875 100644
--- a/examples/bzlmod/test.py
+++ b/examples/bzlmod/test.py
@@ -76,7 +76,7 @@ class ExampleTest(unittest.TestCase):
)
def test_main(self):
- self.assertEquals(
+ self.assertEqual(
"""\
- -
A 1
diff --git a/examples/bzlmod/tests/dupe_requirements/BUILD.bazel b/examples/bzlmod/tests/dupe_requirements/BUILD.bazel
new file mode 100644
index 0000000..47eb7ca
--- /dev/null
+++ b/examples/bzlmod/tests/dupe_requirements/BUILD.bazel
@@ -0,0 +1,19 @@
+load("@rules_python//python:pip.bzl", "compile_pip_requirements")
+load("@rules_python//python:py_test.bzl", "py_test")
+
+py_test(
+ name = "dupe_requirements_test",
+ srcs = ["dupe_requirements_test.py"],
+ deps = [
+ "@dupe_requirements//pyjwt",
+ ],
+)
+
+compile_pip_requirements(
+ name = "requirements",
+ src = "requirements.in",
+ requirements_txt = "requirements.txt",
+ # This is to make the requirements diff test not run on CI. The content we
+ # need in requirements.txt isn't exactly what will be generated.
+ tags = ["manual"],
+)
diff --git a/examples/bzlmod/tests/dupe_requirements/dupe_requirements_test.py b/examples/bzlmod/tests/dupe_requirements/dupe_requirements_test.py
new file mode 100644
index 0000000..1139dc5
--- /dev/null
+++ b/examples/bzlmod/tests/dupe_requirements/dupe_requirements_test.py
@@ -0,0 +1,4 @@
+# There's nothing to test at runtime. Building indicates success.
+# Just import the relevant modules as a basic check.
+import cryptography
+import jwt
diff --git a/examples/bzlmod/tests/dupe_requirements/requirements.in b/examples/bzlmod/tests/dupe_requirements/requirements.in
new file mode 100644
index 0000000..b1f6233
--- /dev/null
+++ b/examples/bzlmod/tests/dupe_requirements/requirements.in
@@ -0,0 +1,2 @@
+pyjwt
+pyjwt[crypto]
diff --git a/examples/bzlmod/tests/dupe_requirements/requirements.txt b/examples/bzlmod/tests/dupe_requirements/requirements.txt
new file mode 100644
index 0000000..785f556
--- /dev/null
+++ b/examples/bzlmod/tests/dupe_requirements/requirements.txt
@@ -0,0 +1,97 @@
+#
+# This file is manually tweaked output from the automatic generation.
+# To generate:
+# 1. bazel run //tests/dupe_requirements:requirements.update
+# 2. Then copy/paste the pyjtw lines so there are duplicates
+#
+pyjwt==2.8.0 \
+ --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \
+ --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320
+ # via -r tests/dupe_requirements/requirements.in
+pyjwt[crypto]==2.8.0 \
+ --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \
+ --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320
+ # via -r tests/dupe_requirements/requirements.in
+cffi==1.16.0 \
+ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
+ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \
+ --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
+ --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
+ --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
+ --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \
+ --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
+ --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \
+ --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \
+ --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
+ --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
+ --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \
+ --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
+ --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
+ --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
+ --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
+ --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \
+ --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
+ --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
+ --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
+ --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \
+ --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \
+ --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
+ --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \
+ --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \
+ --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
+ --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \
+ --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \
+ --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
+ --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
+ --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
+ --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \
+ --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
+ --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
+ --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
+ --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \
+ --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
+ --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \
+ --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
+ --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
+ --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
+ --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \
+ --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
+ --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
+ --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
+ --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
+ --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
+ --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \
+ --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \
+ --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
+ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
+ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
+ # via cryptography
+cryptography==41.0.7 \
+ --hash=sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960 \
+ --hash=sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a \
+ --hash=sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc \
+ --hash=sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a \
+ --hash=sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf \
+ --hash=sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1 \
+ --hash=sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39 \
+ --hash=sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406 \
+ --hash=sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a \
+ --hash=sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a \
+ --hash=sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c \
+ --hash=sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be \
+ --hash=sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15 \
+ --hash=sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2 \
+ --hash=sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d \
+ --hash=sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157 \
+ --hash=sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003 \
+ --hash=sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248 \
+ --hash=sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a \
+ --hash=sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec \
+ --hash=sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309 \
+ --hash=sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7 \
+ --hash=sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d
+ # via pyjwt
+pycparser==2.21 \
+ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
+ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
+ # via cffi
diff --git a/examples/bzlmod/tests/other_module/BUILD.bazel b/examples/bzlmod/tests/other_module/BUILD.bazel
new file mode 100644
index 0000000..1bd8a90
--- /dev/null
+++ b/examples/bzlmod/tests/other_module/BUILD.bazel
@@ -0,0 +1,14 @@
+# Tests to verify the root module can interact with the "other_module"
+# submodule.
+#
+# Note that other_module is seen as "our_other_module" due to repo-remapping
+# in the root module.
+
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+
+build_test(
+ name = "other_module_bin_build_test",
+ targets = [
+ "@our_other_module//other_module/pkg:bin",
+ ],
+)
diff --git a/examples/bzlmod/whl_mods/BUILD.bazel b/examples/bzlmod/whl_mods/BUILD.bazel
index 6ca07dd..241d9c1 100644
--- a/examples/bzlmod/whl_mods/BUILD.bazel
+++ b/examples/bzlmod/whl_mods/BUILD.bazel
@@ -9,8 +9,8 @@ py_test(
name = "pip_whl_mods_test",
srcs = ["pip_whl_mods_test.py"],
env = {
- "REQUESTS_PKG_DIR": "pip_39_requests",
- "WHEEL_PKG_DIR": "pip_39_wheel",
+ "REQUESTS_PKG": "$(rlocationpaths @pip//requests:pkg)",
+ "WHEEL_PKG": "$(rlocationpaths @pip//wheel:pkg)",
},
main = "pip_whl_mods_test.py",
deps = [
diff --git a/examples/bzlmod/whl_mods/appended_build_content.BUILD b/examples/bzlmod/whl_mods/appended_build_content.BUILD
index 7a9f3a2..0ca118d 100644
--- a/examples/bzlmod/whl_mods/appended_build_content.BUILD
+++ b/examples/bzlmod/whl_mods/appended_build_content.BUILD
@@ -5,3 +5,12 @@ write_file(
out = "generated_file.txt",
content = ["Hello world from requests"],
)
+
+filegroup(
+ name = "whl_orig",
+ srcs = glob(
+ ["*.whl"],
+ allow_empty = False,
+ exclude = ["*-patched-*.whl"],
+ ),
+)
diff --git a/examples/bzlmod/whl_mods/pip_whl_mods_test.py b/examples/bzlmod/whl_mods/pip_whl_mods_test.py
index c739b80..3d7d161 100644
--- a/examples/bzlmod/whl_mods/pip_whl_mods_test.py
+++ b/examples/bzlmod/whl_mods/pip_whl_mods_test.py
@@ -27,22 +27,30 @@ from python.runfiles import runfiles
class PipWhlModsTest(unittest.TestCase):
maxDiff = None
- def package_path(self) -> str:
- return "rules_python~override~pip~"
+ @staticmethod
+ def _get_bazel_pkg_dir_name(env_var: str) -> str:
+ a_file = Path(os.environ.get(env_var).split(" ")[0])
+ head = a_file
+ while head.parent.name:
+ head = head.parent
- def wheel_pkg_dir(self) -> str:
- env = os.environ.get("WHEEL_PKG_DIR")
- self.assertIsNotNone(env)
- return env
+ return head.name
+
+ @classmethod
+ def setUpClass(cls):
+ cls._wheel_pkg_dir = cls._get_bazel_pkg_dir_name("WHEEL_PKG")
+ cls._requests_pkg_dir = cls._get_bazel_pkg_dir_name("REQUESTS_PKG")
+
+ def wheel_pkg_dir(self) -> Path:
+ return self._wheel_pkg
def test_build_content_and_data(self):
r = runfiles.Create()
rpath = r.Rlocation(
- "{}{}/generated_file.txt".format(
- self.package_path(),
- self.wheel_pkg_dir(),
- ),
- )
+ "{}/generated_file.txt".format(
+ self._wheel_pkg_dir,
+ ),
+ )
generated_file = Path(rpath)
self.assertTrue(generated_file.exists())
@@ -52,11 +60,10 @@ class PipWhlModsTest(unittest.TestCase):
def test_copy_files(self):
r = runfiles.Create()
rpath = r.Rlocation(
- "{}{}/copied_content/file.txt".format(
- self.package_path(),
- self.wheel_pkg_dir(),
- )
- )
+ "{}/copied_content/file.txt".format(
+ self._wheel_pkg_dir,
+ )
+ )
copied_file = Path(rpath)
self.assertTrue(copied_file.exists())
@@ -64,14 +71,17 @@ class PipWhlModsTest(unittest.TestCase):
self.assertEqual(content, "Hello world from copied file")
def test_copy_executables(self):
+ executable_name = (
+ "executable.exe" if platform.system() == "windows" else "executable.py"
+ )
+
r = runfiles.Create()
rpath = r.Rlocation(
- "{}{}/copied_content/executable{}".format(
- self.package_path(),
- self.wheel_pkg_dir(),
- ".exe" if platform.system() == "windows" else ".py",
- )
- )
+ "{}/copied_content/{}".format(
+ self._wheel_pkg_dir,
+ executable_name,
+ )
+ )
executable = Path(rpath)
self.assertTrue(executable.exists())
@@ -88,11 +98,10 @@ class PipWhlModsTest(unittest.TestCase):
current_wheel_version = "0.40.0"
r = runfiles.Create()
- dist_info_dir = "{}{}/site-packages/wheel-{}.dist-info".format(
- self.package_path(),
- self.wheel_pkg_dir(),
- current_wheel_version,
- )
+ dist_info_dir = "{}/site-packages/wheel-{}.dist-info".format(
+ self._wheel_pkg_dir,
+ current_wheel_version,
+ )
# Note: `METADATA` is important as it's consumed by https://docs.python.org/3/library/importlib.metadata.html
# `METADATA` is expected to be there to show dist-info files are included in the runfiles.
@@ -101,30 +110,42 @@ class PipWhlModsTest(unittest.TestCase):
# However, `WHEEL` was explicitly excluded, so it should be missing
wheel_path = r.Rlocation("{}/WHEEL".format(dist_info_dir))
- self.assertTrue(Path(metadata_path).exists())
- self.assertFalse(Path(wheel_path).exists())
-
- def requests_pkg_dir(self) -> str:
- env = os.environ.get("REQUESTS_PKG_DIR")
- self.assertIsNotNone(env)
- return env
+ self.assertTrue(Path(metadata_path).exists(), f"Could not find {metadata_path}")
+ self.assertFalse(
+ Path(wheel_path).exists(), f"Expected to not find {wheel_path}"
+ )
def test_extra(self):
# This test verifies that annotations work correctly for pip packages with extras
# specified, in this case requests[security].
r = runfiles.Create()
rpath = r.Rlocation(
- "{}{}/generated_file.txt".format(
- self.package_path(),
- self.requests_pkg_dir(),
- ),
- )
+ "{}/generated_file.txt".format(
+ self._requests_pkg_dir,
+ ),
+ )
generated_file = Path(rpath)
self.assertTrue(generated_file.exists())
content = generated_file.read_text().rstrip()
self.assertEqual(content, "Hello world from requests")
+ def test_patches(self):
+ current_wheel_version = "2.25.1"
+
+ # This test verifies that the patches are applied to the wheel.
+ r = runfiles.Create()
+ metadata_path = "{}/site-packages/requests-{}.dist-info/METADATA".format(
+ self._requests_pkg_dir,
+ current_wheel_version,
+ )
+
+ metadata = Path(r.Rlocation(metadata_path))
+ self.assertIn(
+ "Summary: Python HTTP for Humans. Patched.",
+ metadata.read_text().splitlines(),
+ )
+
if __name__ == "__main__":
unittest.main()
diff --git a/examples/bzlmod_build_file_generation/BUILD.bazel b/examples/bzlmod_build_file_generation/BUILD.bazel
index c5e27c2..bca3b36 100644
--- a/examples/bzlmod_build_file_generation/BUILD.bazel
+++ b/examples/bzlmod_build_file_generation/BUILD.bazel
@@ -9,7 +9,6 @@ load("@bazel_gazelle//:def.bzl", "gazelle")
load("@pip//:requirements.bzl", "all_whl_requirements")
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")
@@ -17,8 +16,7 @@ load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")
# with pip-compile.
compile_pip_requirements(
name = "requirements",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock.txt",
requirements_windows = "requirements_windows.txt",
)
@@ -53,9 +51,7 @@ gazelle_python_manifest(
"//:requirements_lock.txt",
"//:requirements_windows.txt",
],
- # NOTE: we can use this flag in order to make our setup compatible with
- # bzlmod.
- use_pip_repository_aliases = True,
+ tags = ["exclusive"],
)
# Our gazelle target points to the python gazelle binary.
@@ -70,7 +66,6 @@ gazelle_python_manifest(
# 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",
)
diff --git a/examples/bzlmod_build_file_generation/__test__.py b/examples/bzlmod_build_file_generation/__test__.py
index cdc1c89..cde1d42 100644
--- a/examples/bzlmod_build_file_generation/__test__.py
+++ b/examples/bzlmod_build_file_generation/__test__.py
@@ -19,7 +19,7 @@ from lib import main
class ExampleTest(unittest.TestCase):
def test_main(self):
- self.assertEquals(
+ self.assertEqual(
"""\
- -
A 1
diff --git a/examples/bzlmod_build_file_generation/gazelle_python.yaml b/examples/bzlmod_build_file_generation/gazelle_python.yaml
index e33021b..46a1c8b 100644
--- a/examples/bzlmod_build_file_generation/gazelle_python.yaml
+++ b/examples/bzlmod_build_file_generation/gazelle_python.yaml
@@ -232,7 +232,6 @@ manifest:
isort.wrap: isort
isort.wrap_modes: isort
lazy_object_proxy: lazy_object_proxy
- lazy_object_proxy.cext: lazy_object_proxy
lazy_object_proxy.compat: lazy_object_proxy
lazy_object_proxy.simple: lazy_object_proxy
lazy_object_proxy.slots: lazy_object_proxy
@@ -587,5 +586,4 @@ manifest:
yamllint.rules.truthy: yamllint
pip_repository:
name: pip
- use_pip_repository_aliases: true
-integrity: cee7684391c4a8a1ff219cd354deae61cdcdee70f2076789aabd5249f3c4eca9
+integrity: cd25503dc6b3d9e1c5f46715ba2d0499ecc8b3d654ebcbf9f4e52f2074290e0a
diff --git a/examples/bzlmod_build_file_generation/requirements_lock.txt b/examples/bzlmod_build_file_generation/requirements_lock.txt
index 2160fe1..3fd053f 100644
--- a/examples/bzlmod_build_file_generation/requirements_lock.txt
+++ b/examples/bzlmod_build_file_generation/requirements_lock.txt
@@ -125,10 +125,6 @@ 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
@@ -225,3 +221,9 @@ yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
diff --git a/examples/bzlmod_build_file_generation/requirements_windows.txt b/examples/bzlmod_build_file_generation/requirements_windows.txt
index 06cfdc3..15e9228 100644
--- a/examples/bzlmod_build_file_generation/requirements_windows.txt
+++ b/examples/bzlmod_build_file_generation/requirements_windows.txt
@@ -129,10 +129,6 @@ 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
@@ -229,3 +225,9 @@ yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
diff --git a/examples/multi_python_versions/MODULE.bazel b/examples/multi_python_versions/MODULE.bazel
new file mode 100644
index 0000000..1e5d32e
--- /dev/null
+++ b/examples/multi_python_versions/MODULE.bazel
@@ -0,0 +1,57 @@
+module(
+ name = "multi_python_versions",
+)
+
+bazel_dep(name = "bazel_skylib", version = "1.4.0")
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+ module_name = "rules_python",
+ path = "../..",
+)
+
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+python.toolchain(
+ configure_coverage_tool = True,
+ python_version = "3.8",
+)
+python.toolchain(
+ configure_coverage_tool = True,
+ # Only set when you have mulitple toolchain versions.
+ is_default = True,
+ python_version = "3.9",
+)
+python.toolchain(
+ configure_coverage_tool = True,
+ python_version = "3.10",
+)
+python.toolchain(
+ configure_coverage_tool = True,
+ python_version = "3.11",
+)
+use_repo(
+ python,
+ python = "python_versions",
+)
+
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+use_repo(pip, "pypi")
+pip.parse(
+ hub_name = "pypi",
+ python_version = "3.8",
+ requirements_lock = "//requirements:requirements_lock_3_8.txt",
+)
+pip.parse(
+ hub_name = "pypi",
+ python_version = "3.9",
+ requirements_lock = "//requirements:requirements_lock_3_9.txt",
+)
+pip.parse(
+ hub_name = "pypi",
+ python_version = "3.10",
+ requirements_lock = "//requirements:requirements_lock_3_10.txt",
+)
+pip.parse(
+ hub_name = "pypi",
+ python_version = "3.11",
+ requirements_lock = "//requirements:requirements_lock_3_11.txt",
+)
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/BUILD.bazel b/examples/multi_python_versions/WORKSPACE.bzlmod
index e69de29..e69de29 100644
--- a/tests/compile_pip_requirements_test_from_external_workspace/BUILD.bazel
+++ b/examples/multi_python_versions/WORKSPACE.bzlmod
diff --git a/examples/multi_python_versions/requirements/BUILD.bazel b/examples/multi_python_versions/requirements/BUILD.bazel
index e3184c8..f67333a 100644
--- a/examples/multi_python_versions/requirements/BUILD.bazel
+++ b/examples/multi_python_versions/requirements/BUILD.bazel
@@ -5,28 +5,24 @@ load("@python//3.9:defs.bzl", compile_pip_requirements_3_9 = "compile_pip_requir
compile_pip_requirements_3_8(
name = "requirements_3_8",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock_3_8.txt",
)
compile_pip_requirements_3_9(
name = "requirements_3_9",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock_3_9.txt",
)
compile_pip_requirements_3_10(
name = "requirements_3_10",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock_3_10.txt",
)
compile_pip_requirements_3_11(
name = "requirements_3_11",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock_3_11.txt",
)
diff --git a/examples/multi_python_versions/requirements/requirements_lock_3_10.txt b/examples/multi_python_versions/requirements/requirements_lock_3_10.txt
index 6bee4e0..4910d13 100644
--- a/examples/multi_python_versions/requirements/requirements_lock_3_10.txt
+++ b/examples/multi_python_versions/requirements/requirements_lock_3_10.txt
@@ -4,53 +4,75 @@
#
# bazel run //requirements:requirements_3_10.update
#
-websockets==10.3 \
- --hash=sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af \
- --hash=sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c \
- --hash=sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76 \
- --hash=sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47 \
- --hash=sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69 \
- --hash=sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079 \
- --hash=sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c \
- --hash=sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55 \
- --hash=sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02 \
- --hash=sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559 \
- --hash=sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3 \
- --hash=sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e \
- --hash=sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978 \
- --hash=sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98 \
- --hash=sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae \
- --hash=sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755 \
- --hash=sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d \
- --hash=sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991 \
- --hash=sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1 \
- --hash=sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680 \
- --hash=sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247 \
- --hash=sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f \
- --hash=sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2 \
- --hash=sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7 \
- --hash=sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4 \
- --hash=sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667 \
- --hash=sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb \
- --hash=sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094 \
- --hash=sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36 \
- --hash=sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79 \
- --hash=sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500 \
- --hash=sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e \
- --hash=sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582 \
- --hash=sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442 \
- --hash=sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd \
- --hash=sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6 \
- --hash=sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731 \
- --hash=sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4 \
- --hash=sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d \
- --hash=sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8 \
- --hash=sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f \
- --hash=sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677 \
- --hash=sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8 \
- --hash=sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9 \
- --hash=sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e \
- --hash=sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b \
- --hash=sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916 \
- --hash=sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4
+websockets==11.0.3 \
+ --hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
+ --hash=sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f \
+ --hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 \
+ --hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 \
+ --hash=sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788 \
+ --hash=sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa \
+ --hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f \
+ --hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 \
+ --hash=sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7 \
+ --hash=sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f \
+ --hash=sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd \
+ --hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 \
+ --hash=sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb \
+ --hash=sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b \
+ --hash=sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016 \
+ --hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac \
+ --hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 \
+ --hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb \
+ --hash=sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99 \
+ --hash=sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e \
+ --hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 \
+ --hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf \
+ --hash=sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007 \
+ --hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 \
+ --hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 \
+ --hash=sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86 \
+ --hash=sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1 \
+ --hash=sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61 \
+ --hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 \
+ --hash=sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8 \
+ --hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f \
+ --hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 \
+ --hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 \
+ --hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 \
+ --hash=sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae \
+ --hash=sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd \
+ --hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b \
+ --hash=sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311 \
+ --hash=sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af \
+ --hash=sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152 \
+ --hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 \
+ --hash=sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de \
+ --hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 \
+ --hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d \
+ --hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d \
+ --hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca \
+ --hash=sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0 \
+ --hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 \
+ --hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b \
+ --hash=sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e \
+ --hash=sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128 \
+ --hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d \
+ --hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c \
+ --hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 \
+ --hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 \
+ --hash=sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b \
+ --hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b \
+ --hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 \
+ --hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c \
+ --hash=sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c \
+ --hash=sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f \
+ --hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 \
+ --hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 \
+ --hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb \
+ --hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 \
+ --hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf \
+ --hash=sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0 \
+ --hash=sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74 \
+ --hash=sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0 \
+ --hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564
# via -r requirements/requirements.in
diff --git a/examples/multi_python_versions/requirements/requirements_lock_3_11.txt b/examples/multi_python_versions/requirements/requirements_lock_3_11.txt
index a437a39..35666b5 100644
--- a/examples/multi_python_versions/requirements/requirements_lock_3_11.txt
+++ b/examples/multi_python_versions/requirements/requirements_lock_3_11.txt
@@ -4,53 +4,75 @@
#
# bazel run //requirements:requirements_3_11.update
#
-websockets==10.3 \
- --hash=sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af \
- --hash=sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c \
- --hash=sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76 \
- --hash=sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47 \
- --hash=sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69 \
- --hash=sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079 \
- --hash=sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c \
- --hash=sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55 \
- --hash=sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02 \
- --hash=sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559 \
- --hash=sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3 \
- --hash=sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e \
- --hash=sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978 \
- --hash=sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98 \
- --hash=sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae \
- --hash=sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755 \
- --hash=sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d \
- --hash=sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991 \
- --hash=sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1 \
- --hash=sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680 \
- --hash=sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247 \
- --hash=sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f \
- --hash=sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2 \
- --hash=sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7 \
- --hash=sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4 \
- --hash=sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667 \
- --hash=sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb \
- --hash=sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094 \
- --hash=sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36 \
- --hash=sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79 \
- --hash=sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500 \
- --hash=sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e \
- --hash=sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582 \
- --hash=sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442 \
- --hash=sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd \
- --hash=sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6 \
- --hash=sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731 \
- --hash=sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4 \
- --hash=sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d \
- --hash=sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8 \
- --hash=sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f \
- --hash=sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677 \
- --hash=sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8 \
- --hash=sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9 \
- --hash=sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e \
- --hash=sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b \
- --hash=sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916 \
- --hash=sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4
+websockets==11.0.3 \
+ --hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
+ --hash=sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f \
+ --hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 \
+ --hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 \
+ --hash=sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788 \
+ --hash=sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa \
+ --hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f \
+ --hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 \
+ --hash=sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7 \
+ --hash=sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f \
+ --hash=sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd \
+ --hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 \
+ --hash=sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb \
+ --hash=sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b \
+ --hash=sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016 \
+ --hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac \
+ --hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 \
+ --hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb \
+ --hash=sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99 \
+ --hash=sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e \
+ --hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 \
+ --hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf \
+ --hash=sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007 \
+ --hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 \
+ --hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 \
+ --hash=sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86 \
+ --hash=sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1 \
+ --hash=sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61 \
+ --hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 \
+ --hash=sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8 \
+ --hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f \
+ --hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 \
+ --hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 \
+ --hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 \
+ --hash=sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae \
+ --hash=sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd \
+ --hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b \
+ --hash=sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311 \
+ --hash=sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af \
+ --hash=sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152 \
+ --hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 \
+ --hash=sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de \
+ --hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 \
+ --hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d \
+ --hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d \
+ --hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca \
+ --hash=sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0 \
+ --hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 \
+ --hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b \
+ --hash=sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e \
+ --hash=sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128 \
+ --hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d \
+ --hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c \
+ --hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 \
+ --hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 \
+ --hash=sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b \
+ --hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b \
+ --hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 \
+ --hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c \
+ --hash=sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c \
+ --hash=sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f \
+ --hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 \
+ --hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 \
+ --hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb \
+ --hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 \
+ --hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf \
+ --hash=sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0 \
+ --hash=sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74 \
+ --hash=sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0 \
+ --hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564
# via -r requirements/requirements.in
diff --git a/examples/multi_python_versions/requirements/requirements_lock_3_8.txt b/examples/multi_python_versions/requirements/requirements_lock_3_8.txt
index 19303f8..10b5df4 100644
--- a/examples/multi_python_versions/requirements/requirements_lock_3_8.txt
+++ b/examples/multi_python_versions/requirements/requirements_lock_3_8.txt
@@ -4,53 +4,75 @@
#
# bazel run //requirements:requirements_3_8.update
#
-websockets==10.3 \
- --hash=sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af \
- --hash=sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c \
- --hash=sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76 \
- --hash=sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47 \
- --hash=sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69 \
- --hash=sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079 \
- --hash=sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c \
- --hash=sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55 \
- --hash=sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02 \
- --hash=sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559 \
- --hash=sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3 \
- --hash=sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e \
- --hash=sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978 \
- --hash=sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98 \
- --hash=sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae \
- --hash=sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755 \
- --hash=sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d \
- --hash=sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991 \
- --hash=sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1 \
- --hash=sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680 \
- --hash=sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247 \
- --hash=sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f \
- --hash=sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2 \
- --hash=sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7 \
- --hash=sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4 \
- --hash=sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667 \
- --hash=sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb \
- --hash=sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094 \
- --hash=sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36 \
- --hash=sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79 \
- --hash=sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500 \
- --hash=sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e \
- --hash=sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582 \
- --hash=sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442 \
- --hash=sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd \
- --hash=sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6 \
- --hash=sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731 \
- --hash=sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4 \
- --hash=sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d \
- --hash=sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8 \
- --hash=sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f \
- --hash=sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677 \
- --hash=sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8 \
- --hash=sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9 \
- --hash=sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e \
- --hash=sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b \
- --hash=sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916 \
- --hash=sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4
+websockets==11.0.3 \
+ --hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
+ --hash=sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f \
+ --hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 \
+ --hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 \
+ --hash=sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788 \
+ --hash=sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa \
+ --hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f \
+ --hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 \
+ --hash=sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7 \
+ --hash=sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f \
+ --hash=sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd \
+ --hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 \
+ --hash=sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb \
+ --hash=sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b \
+ --hash=sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016 \
+ --hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac \
+ --hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 \
+ --hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb \
+ --hash=sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99 \
+ --hash=sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e \
+ --hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 \
+ --hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf \
+ --hash=sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007 \
+ --hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 \
+ --hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 \
+ --hash=sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86 \
+ --hash=sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1 \
+ --hash=sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61 \
+ --hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 \
+ --hash=sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8 \
+ --hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f \
+ --hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 \
+ --hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 \
+ --hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 \
+ --hash=sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae \
+ --hash=sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd \
+ --hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b \
+ --hash=sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311 \
+ --hash=sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af \
+ --hash=sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152 \
+ --hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 \
+ --hash=sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de \
+ --hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 \
+ --hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d \
+ --hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d \
+ --hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca \
+ --hash=sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0 \
+ --hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 \
+ --hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b \
+ --hash=sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e \
+ --hash=sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128 \
+ --hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d \
+ --hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c \
+ --hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 \
+ --hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 \
+ --hash=sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b \
+ --hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b \
+ --hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 \
+ --hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c \
+ --hash=sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c \
+ --hash=sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f \
+ --hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 \
+ --hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 \
+ --hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb \
+ --hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 \
+ --hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf \
+ --hash=sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0 \
+ --hash=sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74 \
+ --hash=sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0 \
+ --hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564
# via -r requirements/requirements.in
diff --git a/examples/multi_python_versions/requirements/requirements_lock_3_9.txt b/examples/multi_python_versions/requirements/requirements_lock_3_9.txt
index 4af42ca..0001f88 100644
--- a/examples/multi_python_versions/requirements/requirements_lock_3_9.txt
+++ b/examples/multi_python_versions/requirements/requirements_lock_3_9.txt
@@ -4,53 +4,75 @@
#
# bazel run //requirements:requirements_3_9.update
#
-websockets==10.3 \
- --hash=sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af \
- --hash=sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c \
- --hash=sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76 \
- --hash=sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47 \
- --hash=sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69 \
- --hash=sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079 \
- --hash=sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c \
- --hash=sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55 \
- --hash=sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02 \
- --hash=sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559 \
- --hash=sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3 \
- --hash=sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e \
- --hash=sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978 \
- --hash=sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98 \
- --hash=sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae \
- --hash=sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755 \
- --hash=sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d \
- --hash=sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991 \
- --hash=sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1 \
- --hash=sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680 \
- --hash=sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247 \
- --hash=sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f \
- --hash=sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2 \
- --hash=sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7 \
- --hash=sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4 \
- --hash=sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667 \
- --hash=sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb \
- --hash=sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094 \
- --hash=sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36 \
- --hash=sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79 \
- --hash=sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500 \
- --hash=sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e \
- --hash=sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582 \
- --hash=sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442 \
- --hash=sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd \
- --hash=sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6 \
- --hash=sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731 \
- --hash=sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4 \
- --hash=sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d \
- --hash=sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8 \
- --hash=sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f \
- --hash=sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677 \
- --hash=sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8 \
- --hash=sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9 \
- --hash=sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e \
- --hash=sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b \
- --hash=sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916 \
- --hash=sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4
+websockets==11.0.3 \
+ --hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
+ --hash=sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f \
+ --hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 \
+ --hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 \
+ --hash=sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788 \
+ --hash=sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa \
+ --hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f \
+ --hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 \
+ --hash=sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7 \
+ --hash=sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f \
+ --hash=sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd \
+ --hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 \
+ --hash=sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb \
+ --hash=sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b \
+ --hash=sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016 \
+ --hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac \
+ --hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 \
+ --hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb \
+ --hash=sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99 \
+ --hash=sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e \
+ --hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 \
+ --hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf \
+ --hash=sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007 \
+ --hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 \
+ --hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 \
+ --hash=sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86 \
+ --hash=sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1 \
+ --hash=sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61 \
+ --hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 \
+ --hash=sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8 \
+ --hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f \
+ --hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 \
+ --hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 \
+ --hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 \
+ --hash=sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae \
+ --hash=sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd \
+ --hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b \
+ --hash=sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311 \
+ --hash=sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af \
+ --hash=sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152 \
+ --hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 \
+ --hash=sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de \
+ --hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 \
+ --hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d \
+ --hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d \
+ --hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca \
+ --hash=sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0 \
+ --hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 \
+ --hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b \
+ --hash=sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e \
+ --hash=sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128 \
+ --hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d \
+ --hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c \
+ --hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 \
+ --hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 \
+ --hash=sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b \
+ --hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b \
+ --hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 \
+ --hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c \
+ --hash=sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c \
+ --hash=sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f \
+ --hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 \
+ --hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 \
+ --hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb \
+ --hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 \
+ --hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf \
+ --hash=sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0 \
+ --hash=sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74 \
+ --hash=sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0 \
+ --hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564
# via -r requirements/requirements.in
diff --git a/examples/multi_python_versions/tests/my_lib_test.py b/examples/multi_python_versions/tests/my_lib_test.py
index e0a97db..1d4880f 100644
--- a/examples/multi_python_versions/tests/my_lib_test.py
+++ b/examples/multi_python_versions/tests/my_lib_test.py
@@ -17,8 +17,11 @@ import sys
import libs.my_lib as my_lib
-sanitized_version_check = f"{sys.version_info.major}_{sys.version_info.minor}"
+workspace_version = f"{sys.version_info.major}_{sys.version_info.minor}"
+bzlmod_version = f"{sys.version_info.major}{sys.version_info.minor}"
-if not my_lib.websockets_is_for_python_version(sanitized_version_check):
+if not my_lib.websockets_is_for_python_version(
+ workspace_version
+) and not my_lib.websockets_is_for_python_version(bzlmod_version):
print("expected package for Python version is different than returned")
sys.exit(1)
diff --git a/examples/pip_install/.bazelrc b/examples/pip_install/.bazelrc
deleted file mode 100644
index 9e7ef37..0000000
--- a/examples/pip_install/.bazelrc
+++ /dev/null
@@ -1,2 +0,0 @@
-# https://docs.bazel.build/versions/main/best-practices.html#using-the-bazelrc-file
-try-import %workspace%/user.bazelrc
diff --git a/examples/pip_install/BUILD.bazel b/examples/pip_install/BUILD.bazel
deleted file mode 100644
index 35f5a93..0000000
--- a/examples/pip_install/BUILD.bazel
+++ /dev/null
@@ -1,111 +0,0 @@
-load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
-load("@bazel_skylib//rules:write_file.bzl", "write_file")
-load(
- "@pip//:requirements.bzl",
- "data_requirement",
- "dist_info_requirement",
- "entry_point",
- "requirement",
-)
-load("@rules_python//python:defs.bzl", "py_binary", "py_test")
-load("@rules_python//python:pip.bzl", "compile_pip_requirements")
-
-# Toolchain setup, this is optional.
-# Demonstrate that we can use the same python interpreter for the toolchain and executing pip in pip install (see WORKSPACE).
-#
-#load("@rules_python//python:defs.bzl", "py_runtime_pair")
-#
-#py_runtime(
-# name = "python3_runtime",
-# files = ["@python_interpreter//:files"],
-# interpreter = "@python_interpreter//:python_bin",
-# python_version = "PY3",
-# visibility = ["//visibility:public"],
-#)
-#
-#py_runtime_pair(
-# name = "my_py_runtime_pair",
-# py2_runtime = None,
-# py3_runtime = ":python3_runtime",
-#)
-#
-#toolchain(
-# name = "my_py_toolchain",
-# toolchain = ":my_py_runtime_pair",
-# toolchain_type = "@bazel_tools//tools/python:toolchain_type",
-#)
-# End of toolchain setup.
-
-py_binary(
- name = "main",
- srcs = ["main.py"],
- deps = [
- requirement("boto3"),
- ],
-)
-
-py_test(
- name = "test",
- srcs = ["test.py"],
- deps = [":main"],
-)
-
-# For pip dependencies which have entry points, the `entry_point` macro can be
-# used from the generated `pip_install` repository to access a runnable binary.
-
-alias(
- name = "yamllint",
- actual = entry_point("yamllint"),
-)
-
-# Check that our compiled requirements are up-to-date
-compile_pip_requirements(
- name = "requirements",
- extra_args = ["--allow-unsafe"],
- requirements_windows = ":requirements_windows.txt",
-)
-
-# Test the use of all pip_install utilities in a single py_test
-py_test(
- name = "pip_install_test",
- srcs = ["pip_install_test.py"],
- data = [
- ":yamllint",
- data_requirement("s3cmd"),
- dist_info_requirement("boto3"),
- ],
- env = {
- "WHEEL_DATA_CONTENTS": "$(rootpaths {})".format(data_requirement("s3cmd")),
- "WHEEL_DIST_INFO_CONTENTS": "$(rootpaths {})".format(dist_info_requirement("boto3")),
- "YAMLLINT_ENTRY_POINT": "$(rootpath :yamllint)",
- },
- deps = ["@rules_python//python/runfiles"],
-)
-
-# Assert that tags are present on resulting py_library,
-# which is useful for tooling that needs to reflect on the dep graph
-# to determine the packages it was built from.
-genquery(
- name = "yamllint_lib_by_version",
- expression = """
- attr("tags", "\\bpypi_version=1.26.3\\b", "@pip_yamllint//:pkg")
- intersect
- attr("tags", "\\bpypi_name=yamllint\\b", "@pip_yamllint//:pkg")
- """,
- scope = [requirement("yamllint")],
-)
-
-write_file(
- name = "write_expected",
- out = "expected",
- content = [
- "@pip_yamllint//:pkg",
- "",
- ],
-)
-
-diff_test(
- name = "test_query_result",
- file1 = "expected",
- file2 = "yamllint_lib_by_version",
-)
diff --git a/examples/pip_install/README.md b/examples/pip_install/README.md
deleted file mode 100644
index 7657787..0000000
--- a/examples/pip_install/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# pip_install example
-
-This example shows how to use pip to fetch external dependencies from a requirements.txt file,
-then use them in BUILD files as dependencies of Bazel targets.
diff --git a/examples/pip_install/WORKSPACE b/examples/pip_install/WORKSPACE
deleted file mode 100644
index b1744bf..0000000
--- a/examples/pip_install/WORKSPACE
+++ /dev/null
@@ -1,96 +0,0 @@
-workspace(name = "rules_python_pip_install_example")
-
-local_repository(
- name = "rules_python",
- path = "../..",
-)
-
-load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
-
-py_repositories()
-
-python_register_toolchains(
- name = "python39",
- python_version = "3.9",
-)
-
-load("@python39//:defs.bzl", "interpreter")
-load("@rules_python//python:pip.bzl", "pip_install")
-
-pip_install(
- # (Optional) You can provide extra parameters to pip.
- # Here, make pip output verbose (this is usable with `quiet = False`).
- #extra_pip_args = ["-v"],
-
- # (Optional) You can exclude custom elements in the data section of the generated BUILD files for pip packages.
- # Exclude directories with spaces in their names in this example (avoids build errors if there are such directories).
- #pip_data_exclude = ["**/* */**"],
-
- # (Optional) You can provide a python_interpreter (path) or a python_interpreter_target (a Bazel target, that
- # acts as an executable). The latter can be anything that could be used as Python interpreter. E.g.:
- # 1. Python interpreter that you compile in the build file (as above in @python_interpreter).
- # 2. Pre-compiled python interpreter included with http_archive
- # 3. Wrapper script, like in the autodetecting python toolchain.
- #
- # Here, we use the interpreter constant that resolves to the host interpreter from the default Python toolchain.
- python_interpreter_target = interpreter,
-
- # (Optional) You can set quiet to False if you want to see pip output.
- #quiet = False,
-
- # (Optional) You can set an environment in the pip process to control its
- # behavior. Note that pip is run in "isolated" mode so no PIP_<VAR>_<NAME>
- # style env vars are read, but env vars that control requests and urllib3
- # can be passed.
- #environment = {"HTTP_PROXY": "http://my.proxy.fun/"},
-
- # Uses the default repository name "pip"
- requirements = "//:requirements.txt",
-)
-
-load("@pip//:requirements.bzl", "install_deps")
-
-# Initialize repositories for all packages in requirements.txt.
-install_deps()
-
-# You could optionally use an in-build, compiled python interpreter as a toolchain,
-# and also use it to execute pip.
-#
-# Special logic for building python interpreter with OpenSSL from homebrew.
-# See https://devguide.python.org/setup/#macos-and-os-x
-#_py_configure = """
-#if [[ "$OSTYPE" == "darwin"* ]]; then
-# ./configure --prefix=$(pwd)/bazel_install --with-openssl=$(brew --prefix openssl)
-#else
-# ./configure --prefix=$(pwd)/bazel_install
-#fi
-#"""
-#
-# NOTE: you need to have the SSL headers installed to build with openssl support (and use HTTPS).
-# E.g. on Ubuntu: `sudo apt install libssl-dev`
-#http_archive(
-# name = "python_interpreter",
-# build_file_content = """
-#exports_files(["python_bin"])
-#filegroup(
-# name = "files",
-# srcs = glob(["bazel_install/**"], exclude = ["**/* *"]),
-# visibility = ["//visibility:public"],
-#)
-#""",
-# patch_cmds = [
-# "mkdir $(pwd)/bazel_install",
-# _py_configure,
-# "make",
-# "make install",
-# "ln -s bazel_install/bin/python3 python_bin",
-# ],
-# sha256 = "dfab5ec723c218082fe3d5d7ae17ecbdebffa9a1aea4d64aa3a2ecdd2e795864",
-# strip_prefix = "Python-3.8.3",
-# urls = ["https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tar.xz"],
-#)
-
-# Optional:
-# Register the toolchain with the same python interpreter we used for pip in pip_install().
-#register_toolchains("//:my_py_toolchain")
-# End of in-build Python interpreter setup.
diff --git a/examples/pip_install/pip_install_test.py b/examples/pip_install/pip_install_test.py
deleted file mode 100644
index 3e1b085..0000000
--- a/examples/pip_install/pip_install_test.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python3
-# 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 subprocess
-import unittest
-from pathlib import Path
-
-from rules_python.python.runfiles import runfiles
-
-
-class PipInstallTest(unittest.TestCase):
- maxDiff = None
-
- def test_entry_point(self):
- env = os.environ.get("YAMLLINT_ENTRY_POINT")
- self.assertIsNotNone(env)
-
- r = runfiles.Create()
-
- # To find an external target, this must use `{workspace_name}/$(rootpath @external_repo//:target)`
- entry_point = Path(
- r.Rlocation("rules_python_pip_install_example/{}".format(env))
- )
- self.assertTrue(entry_point.exists())
-
- 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.26.3")
-
- def test_data(self):
- env = os.environ.get("WHEEL_DATA_CONTENTS")
- self.assertIsNotNone(env)
- self.assertListEqual(
- env.split(" "),
- [
- "external/pip_s3cmd/data/share/doc/packages/s3cmd/INSTALL.md",
- "external/pip_s3cmd/data/share/doc/packages/s3cmd/LICENSE",
- "external/pip_s3cmd/data/share/doc/packages/s3cmd/NEWS",
- "external/pip_s3cmd/data/share/doc/packages/s3cmd/README.md",
- "external/pip_s3cmd/data/share/man/man1/s3cmd.1",
- ],
- )
-
- def test_dist_info(self):
- env = os.environ.get("WHEEL_DIST_INFO_CONTENTS")
- self.assertIsNotNone(env)
- self.assertListEqual(
- env.split(" "),
- [
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/DESCRIPTION.rst",
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/INSTALLER",
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/METADATA",
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/RECORD",
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/WHEEL",
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/metadata.json",
- "external/pip_boto3/site-packages/boto3-1.14.63.dist-info/top_level.txt",
- ],
- )
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/examples/pip_install/requirements.in b/examples/pip_install/requirements.in
deleted file mode 100644
index 11ede3c..0000000
--- a/examples/pip_install/requirements.in
+++ /dev/null
@@ -1,4 +0,0 @@
-boto3~=1.14.51
-s3cmd~=2.1.0
-yamllint~=1.26.3
-tree-sitter==0.20.0 ; sys_platform != "win32"
diff --git a/examples/pip_install/requirements.txt b/examples/pip_install/requirements.txt
deleted file mode 100644
index 495a32a..0000000
--- a/examples/pip_install/requirements.txt
+++ /dev/null
@@ -1,110 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.9
-# by the following command:
-#
-# bazel run //:requirements.update
-#
-boto3==1.14.63 \
- --hash=sha256:25c716b7c01d4664027afc6a6418a06459e311a610c7fd39a030a1ced1b72ce4 \
- --hash=sha256:37158c37a151eab5b9080968305621a40168171fda9584d50a309ceb4e5e6964
- # via -r requirements.in
-botocore==1.17.63 \
- --hash=sha256:40f13f6c9c29c307a9dc5982739e537ddce55b29787b90c3447b507e3283bcd6 \
- --hash=sha256:aa88eafc6295132f4bc606f1df32b3248e0fa611724c0a216aceda767948ac75
- # via
- # boto3
- # s3transfer
-docutils==0.15.2 \
- --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
- --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
- --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
- # via botocore
-jmespath==0.10.0 \
- --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \
- --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f
- # via
- # boto3
- # botocore
-pathspec==0.10.3 \
- --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
- --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
- # via yamllint
-python-dateutil==2.8.2 \
- --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
- --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
- # via
- # botocore
- # 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
-s3cmd==2.1.0 \
- --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
- --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r requirements.in
-s3transfer==0.3.7 \
- --hash=sha256:35627b86af8ff97e7ac27975fe0a98a312814b46c6333d8a6b889627bcd80994 \
- --hash=sha256:efa5bd92a897b6a8d5c1383828dca3d52d0790e0756d49740563a3fb6ed03246
- # via boto3
-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
-tree-sitter==0.20.0 ; sys_platform != "win32" \
- --hash=sha256:1940f64be1e8c9c3c0e34a2258f1e4c324207534d5b1eefc5ab2960a9d98f668 \
- --hash=sha256:51a609a7c1bd9d9e75d92ee128c12c7852ae70a482900fbbccf3d13a79e0378c
- # 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
diff --git a/examples/pip_install/requirements_windows.txt b/examples/pip_install/requirements_windows.txt
deleted file mode 100644
index b87192f..0000000
--- a/examples/pip_install/requirements_windows.txt
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.9
-# by the following command:
-#
-# bazel run //:requirements.update
-#
-boto3==1.14.63 \
- --hash=sha256:25c716b7c01d4664027afc6a6418a06459e311a610c7fd39a030a1ced1b72ce4 \
- --hash=sha256:37158c37a151eab5b9080968305621a40168171fda9584d50a309ceb4e5e6964
- # via -r requirements.in
-botocore==1.17.63 \
- --hash=sha256:40f13f6c9c29c307a9dc5982739e537ddce55b29787b90c3447b507e3283bcd6 \
- --hash=sha256:aa88eafc6295132f4bc606f1df32b3248e0fa611724c0a216aceda767948ac75
- # via
- # boto3
- # s3transfer
-docutils==0.15.2 \
- --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
- --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
- --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
- # via botocore
-jmespath==0.10.0 \
- --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \
- --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f
- # via
- # boto3
- # botocore
-pathspec==0.10.3 \
- --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
- --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
- # via yamllint
-python-dateutil==2.8.2 \
- --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
- --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
- # via
- # botocore
- # 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
-s3cmd==2.1.0 \
- --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
- --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
- # via -r requirements.in
-s3transfer==0.3.7 \
- --hash=sha256:35627b86af8ff97e7ac27975fe0a98a312814b46c6333d8a6b889627bcd80994 \
- --hash=sha256:efa5bd92a897b6a8d5c1383828dca3d52d0790e0756d49740563a3fb6ed03246
- # via boto3
-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
-urllib3==1.25.11 \
- --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
- --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e
- # via botocore
-yamllint==1.26.3 \
- --hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
- # via -r requirements.in
diff --git a/examples/pip_parse/BUILD.bazel b/examples/pip_parse/BUILD.bazel
index 653f75c..367a795 100644
--- a/examples/pip_parse/BUILD.bazel
+++ b/examples/pip_parse/BUILD.bazel
@@ -1,11 +1,6 @@
-load(
- "@pypi//:requirements.bzl",
- "data_requirement",
- "dist_info_requirement",
- "entry_point",
-)
load("@rules_python//python:defs.bzl", "py_binary", "py_test")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
+load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
# Toolchain setup, this is optional.
# Demonstrate that we can use the same python interpreter for the toolchain and executing pip in pip install (see WORKSPACE).
@@ -37,7 +32,9 @@ py_binary(
name = "main",
srcs = ["main.py"],
deps = [
- "@pypi_requests//:pkg",
+ "@pypi//requests:pkg",
+ "@pypi//sphinx:pkg",
+ "@pypi//sphinxcontrib_serializinghtml:pkg",
],
)
@@ -50,17 +47,17 @@ py_test(
# For pip dependencies which have entry points, the `entry_point` macro can be
# used from the generated `pip_parse` repository to access a runnable binary.
-alias(
+py_console_script_binary(
name = "yamllint",
- actual = entry_point("yamllint"),
+ pkg = "@pypi//yamllint",
)
# This rule adds a convenient way to update the requirements file.
compile_pip_requirements(
name = "requirements",
- extra_args = ["--allow-unsafe"],
- requirements_in = "requirements.in",
+ src = "requirements.in",
requirements_txt = "requirements_lock.txt",
+ requirements_windows = "requirements_windows.txt",
)
# Test the use of all pip_parse utilities in a single py_test
@@ -69,13 +66,13 @@ py_test(
srcs = ["pip_parse_test.py"],
data = [
":yamllint",
- data_requirement("s3cmd"),
- dist_info_requirement("requests"),
+ "@pypi//requests:dist_info",
+ "@pypi//s3cmd:data",
],
env = {
- "WHEEL_DATA_CONTENTS": "$(rootpaths {})".format(data_requirement("s3cmd")),
- "WHEEL_DIST_INFO_CONTENTS": "$(rootpaths {})".format(dist_info_requirement("requests")),
- "YAMLLINT_ENTRY_POINT": "$(rootpath :yamllint)",
+ "WHEEL_DATA_CONTENTS": "$(rootpaths @pypi//s3cmd:data)",
+ "WHEEL_DIST_INFO_CONTENTS": "$(rootpaths @pypi//requests:dist_info)",
+ "YAMLLINT_ENTRY_POINT": "$(rlocationpath :yamllint)",
},
deps = ["@rules_python//python/runfiles"],
)
diff --git a/examples/pip_parse/MODULE.bazel b/examples/pip_parse/MODULE.bazel
new file mode 100644
index 0000000..3977f8a
--- /dev/null
+++ b/examples/pip_parse/MODULE.bazel
@@ -0,0 +1,31 @@
+module(name = "rules_python_pip_parse_example")
+
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+ module_name = "rules_python",
+ path = "../..",
+)
+
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+python.toolchain(
+ python_version = "3.9",
+)
+
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+pip.parse(
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-serializinghtml",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ ],
+ },
+ hub_name = "pypi",
+ python_version = "3.9",
+ requirements_lock = "//:requirements_lock.txt",
+ requirements_windows = "//:requirements_windows.txt",
+)
+use_repo(pip, "pypi")
diff --git a/examples/pip_parse/WORKSPACE b/examples/pip_parse/WORKSPACE
index 79aca14..415d064 100644
--- a/examples/pip_parse/WORKSPACE
+++ b/examples/pip_parse/WORKSPACE
@@ -24,6 +24,19 @@ pip_parse(
# can be passed
# environment = {"HTTPS_PROXY": "http://my.proxy.fun/"},
name = "pypi",
+
+ # Requirement groups allow Bazel to tolerate PyPi cycles by putting dependencies
+ # which are known to form cycles into groups together.
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-qthelp",
+ "sphinxcontrib-htmlhelp",
+ "sphinxcontrib-devhelp",
+ "sphinxcontrib-applehelp",
+ "sphinxcontrib-serializinghtml",
+ ],
+ },
# (Optional) You can provide extra parameters to pip.
# Here, make pip output verbose (this is usable with `quiet = False`).
# extra_pip_args = ["-v"],
@@ -44,6 +57,7 @@ pip_parse(
# (Optional) You can set quiet to False if you want to see pip output.
#quiet = False,
requirements_lock = "//:requirements_lock.txt",
+ requirements_windows = "//:requirements_windows.txt",
)
load("@pypi//:requirements.bzl", "install_deps")
diff --git a/examples/pip_parse/WORKSPACE.bzlmod b/examples/pip_parse/WORKSPACE.bzlmod
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/pip_parse/WORKSPACE.bzlmod
diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py
index f319cb8..79e1a75 100644
--- a/examples/pip_parse/pip_parse_test.py
+++ b/examples/pip_parse/pip_parse_test.py
@@ -19,20 +19,27 @@ import subprocess
import unittest
from pathlib import Path
-from rules_python.python.runfiles import runfiles
+from python.runfiles import runfiles
class PipInstallTest(unittest.TestCase):
maxDiff = None
+ def _remove_leading_dirs(self, paths):
+ # Removes the first two directories (external/<reponame>)
+ # to normalize what workspace and bzlmod produce.
+ return [
+ '/'.join(v.split('/')[2:])
+ for v in paths
+ ]
+
def test_entry_point(self):
- env = os.environ.get("YAMLLINT_ENTRY_POINT")
- self.assertIsNotNone(env)
+ entry_point_path = os.environ.get("YAMLLINT_ENTRY_POINT")
+ self.assertIsNotNone(entry_point_path)
r = runfiles.Create()
- # To find an external target, this must use `{workspace_name}/$(rootpath @external_repo//:target)`
- entry_point = Path(r.Rlocation("rules_python_pip_parse_example/{}".format(env)))
+ entry_point = Path(r.Rlocation(entry_point_path))
self.assertTrue(entry_point.exists())
proc = subprocess.run(
@@ -41,34 +48,37 @@ class PipInstallTest(unittest.TestCase):
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
- self.assertEqual(proc.stdout.decode("utf-8").strip(), "yamllint 1.26.3")
+ self.assertEqual(proc.stdout.decode("utf-8").strip(), "yamllint 1.28.0")
def test_data(self):
- env = os.environ.get("WHEEL_DATA_CONTENTS")
- self.assertIsNotNone(env)
+ actual = os.environ.get("WHEEL_DATA_CONTENTS")
+ self.assertIsNotNone(actual)
+ actual = self._remove_leading_dirs(actual.split(" "))
+
self.assertListEqual(
- env.split(" "),
+ actual,
[
- "external/pypi_s3cmd/data/share/doc/packages/s3cmd/INSTALL.md",
- "external/pypi_s3cmd/data/share/doc/packages/s3cmd/LICENSE",
- "external/pypi_s3cmd/data/share/doc/packages/s3cmd/NEWS",
- "external/pypi_s3cmd/data/share/doc/packages/s3cmd/README.md",
- "external/pypi_s3cmd/data/share/man/man1/s3cmd.1",
+ "data/share/doc/packages/s3cmd/INSTALL.md",
+ "data/share/doc/packages/s3cmd/LICENSE",
+ "data/share/doc/packages/s3cmd/NEWS",
+ "data/share/doc/packages/s3cmd/README.md",
+ "data/share/man/man1/s3cmd.1",
],
)
def test_dist_info(self):
- env = os.environ.get("WHEEL_DIST_INFO_CONTENTS")
- self.assertIsNotNone(env)
+ actual = os.environ.get("WHEEL_DIST_INFO_CONTENTS")
+ self.assertIsNotNone(actual)
+ actual = self._remove_leading_dirs(actual.split(" "))
self.assertListEqual(
- env.split(" "),
+ actual,
[
- "external/pypi_requests/site-packages/requests-2.25.1.dist-info/INSTALLER",
- "external/pypi_requests/site-packages/requests-2.25.1.dist-info/LICENSE",
- "external/pypi_requests/site-packages/requests-2.25.1.dist-info/METADATA",
- "external/pypi_requests/site-packages/requests-2.25.1.dist-info/RECORD",
- "external/pypi_requests/site-packages/requests-2.25.1.dist-info/WHEEL",
- "external/pypi_requests/site-packages/requests-2.25.1.dist-info/top_level.txt",
+ "site-packages/requests-2.25.1.dist-info/INSTALLER",
+ "site-packages/requests-2.25.1.dist-info/LICENSE",
+ "site-packages/requests-2.25.1.dist-info/METADATA",
+ "site-packages/requests-2.25.1.dist-info/RECORD",
+ "site-packages/requests-2.25.1.dist-info/WHEEL",
+ "site-packages/requests-2.25.1.dist-info/top_level.txt",
],
)
diff --git a/examples/pip_parse/requirements.in b/examples/pip_parse/requirements.in
index ec2102f..9d9e766 100644
--- a/examples/pip_parse/requirements.in
+++ b/examples/pip_parse/requirements.in
@@ -1,3 +1,5 @@
requests~=2.25.1
s3cmd~=2.1.0
-yamllint~=1.26.3
+yamllint~=1.28.0
+sphinx
+sphinxcontrib-serializinghtml
diff --git a/examples/pip_parse/requirements_lock.txt b/examples/pip_parse/requirements_lock.txt
index 3cbe57f..b0eedf3 100644
--- a/examples/pip_parse/requirements_lock.txt
+++ b/examples/pip_parse/requirements_lock.txt
@@ -4,6 +4,14 @@
#
# bazel run //:requirements.update
#
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
certifi==2022.12.7 \
--hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
--hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
@@ -12,14 +20,100 @@ chardet==4.0.0 \
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
# via requests
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
idna==2.10 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
# via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
+importlib-metadata==6.8.0 \
+ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \
+ --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743
+ # via sphinx
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via sphinx
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
pathspec==0.10.3 \
--hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
--hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
# via yamllint
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
@@ -73,23 +167,72 @@ pyyaml==6.0 \
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
- # via -r requirements.in
+ # via
+ # -r requirements.in
+ # sphinx
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
-urllib3==1.26.13 \
- --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
- --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
-yamllint==1.26.3 \
- --hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
+yamllint==1.28.0 \
+ --hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
+ --hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+zipp==3.17.0 \
+ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \
+ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0
+ # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
diff --git a/examples/pip_parse/requirements_windows.txt b/examples/pip_parse/requirements_windows.txt
new file mode 100644
index 0000000..18ab80f
--- /dev/null
+++ b/examples/pip_parse/requirements_windows.txt
@@ -0,0 +1,242 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# bazel run //:requirements.update
+#
+alabaster==0.7.13 \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+ # via sphinx
+babel==2.13.1 \
+ --hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
+ --hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
+ # via sphinx
+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 sphinx
+docutils==0.20.1 \
+ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
+ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+ # via sphinx
+idna==2.10 \
+ --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
+ --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
+ # via requests
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+ # via sphinx
+importlib-metadata==6.8.0 \
+ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \
+ --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743
+ # via sphinx
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via sphinx
+markupsafe==2.1.3 \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
+ --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
+ --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+ # via jinja2
+packaging==23.2 \
+ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
+ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+ # via sphinx
+pathspec==0.10.3 \
+ --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \
+ --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6
+ # via yamllint
+pygments==2.16.1 \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+ # via sphinx
+python-dateutil==2.8.2 \
+ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
+ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
+ # via 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
+ # sphinx
+s3cmd==2.1.0 \
+ --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
+ --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
+ # via -r requirements.in
+six==1.16.0 \
+ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+ # via python-dateutil
+snowballstemmer==2.2.0 \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+ # via sphinx
+sphinx==7.2.6 \
+ --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
+ --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+ # via
+ # -r requirements.in
+ # sphinxcontrib-applehelp
+ # sphinxcontrib-devhelp
+ # sphinxcontrib-htmlhelp
+ # sphinxcontrib-qthelp
+ # sphinxcontrib-serializinghtml
+sphinxcontrib-applehelp==1.0.7 \
+ --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
+ --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+ # via sphinx
+sphinxcontrib-devhelp==1.0.5 \
+ --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
+ --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.4 \
+ --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
+ --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+ # via sphinx
+sphinxcontrib-qthelp==1.0.6 \
+ --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
+ --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.9 \
+ --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
+ --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+ # via
+ # -r requirements.in
+ # sphinx
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
+ # via requests
+yamllint==1.28.0 \
+ --hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
+ --hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
+ # via -r requirements.in
+zipp==3.17.0 \
+ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \
+ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0
+ # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.6.3 \
+ --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \
+ --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75
+ # via yamllint
diff --git a/examples/pip_parse_vendored/.bazelrc b/examples/pip_parse_vendored/.bazelrc
index f23315a..b90bf8f 100644
--- a/examples/pip_parse_vendored/.bazelrc
+++ b/examples/pip_parse_vendored/.bazelrc
@@ -3,3 +3,7 @@ test --test_output=errors
# Windows requires these for multi-python support:
build --enable_runfiles
startup --windows_enable_symlinks
+
+# Vendoring requirements.bzl files isn't necessary under bzlmod
+# When workspace support is dropped, this example can be removed.
+build --noexperimental_enable_bzlmod
diff --git a/examples/pip_parse_vendored/BUILD.bazel b/examples/pip_parse_vendored/BUILD.bazel
index 56630e5..ddf3281 100644
--- a/examples/pip_parse_vendored/BUILD.bazel
+++ b/examples/pip_parse_vendored/BUILD.bazel
@@ -4,7 +4,10 @@ load("@rules_python//python:pip.bzl", "compile_pip_requirements")
# This rule adds a convenient way to update the requirements.txt
# lockfile based on the requirements.in.
-compile_pip_requirements(name = "requirements")
+compile_pip_requirements(
+ name = "requirements",
+ src = "requirements.in",
+)
# The requirements.bzl file is generated with a reference to the interpreter for the host platform.
# In order to check in a platform-agnostic file, we have to replace that reference with the symbol
@@ -16,7 +19,7 @@ genrule(
cmd = " | ".join([
"cat $<",
# Insert our load statement after the existing one so we don't produce a file with buildifier warnings
- """sed -e '/^load.*/i\\'$$'\\n''load("@python39//:defs.bzl", "interpreter")'""",
+ """sed -e '/^load.*.pip.bzl/i\\'$$'\\n''load("@python39//:defs.bzl", "interpreter")'""",
# Replace the bazel 6.0.0 specific comment with something that bazel 5.4.0 would produce.
# This enables this example to be run as a test under bazel 5.4.0.
"""sed -e 's#@//#//#'""",
diff --git a/examples/pip_parse_vendored/requirements.bzl b/examples/pip_parse_vendored/requirements.bzl
index 7bf5170..adbee66 100644
--- a/examples/pip_parse_vendored/requirements.bzl
+++ b/examples/pip_parse_vendored/requirements.bzl
@@ -5,37 +5,37 @@ from //:requirements.txt
"""
load("@python39//:defs.bzl", "interpreter")
-load("@rules_python//python/pip_install:pip_repository.bzl", "whl_library")
+load("@rules_python//python:pip.bzl", "pip_utils")
+load("@rules_python//python/pip_install:pip_repository.bzl", "group_library", "whl_library")
-all_requirements = ["@pip_certifi//:pkg", "@pip_charset_normalizer//:pkg", "@pip_idna//:pkg", "@pip_requests//:pkg", "@pip_urllib3//:pkg"]
+all_requirements = ["@pip//certifi:pkg", "@pip//charset_normalizer:pkg", "@pip//idna:pkg", "@pip//requests:pkg", "@pip//urllib3:pkg"]
-all_whl_requirements = ["@pip_certifi//:whl", "@pip_charset_normalizer//:whl", "@pip_idna//:whl", "@pip_requests//:whl", "@pip_urllib3//:whl"]
+all_whl_requirements_by_package = {"certifi": "@pip//certifi:whl", "charset_normalizer": "@pip//charset_normalizer:whl", "idna": "@pip//idna:whl", "requests": "@pip//requests:whl", "urllib3": "@pip//urllib3:whl"}
-all_data_requirements = ["@pip_certifi//:data", "@pip_charset_normalizer//:data", "@pip_idna//:data", "@pip_requests//:data", "@pip_urllib3//:data"]
+all_whl_requirements = all_whl_requirements_by_package.values()
-_packages = [("pip_certifi", "certifi==2022.12.7 --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"), ("pip_charset_normalizer", "charset-normalizer==2.1.1 --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"), ("pip_idna", "idna==3.4 --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"), ("pip_requests", "requests==2.28.1 --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"), ("pip_urllib3", "urllib3==1.26.13 --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8")]
+all_data_requirements = ["@pip//certifi:data", "@pip//charset_normalizer:data", "@pip//idna:data", "@pip//requests:data", "@pip//urllib3:data"]
+
+_packages = [("pip_certifi", "certifi==2023.7.22 --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"), ("pip_charset_normalizer", "charset-normalizer==2.1.1 --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"), ("pip_idna", "idna==3.4 --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"), ("pip_requests", "requests==2.28.1 --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"), ("pip_urllib3", "urllib3==1.26.13 --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8")]
_config = {"download_only": False, "enable_implicit_namespace_pkgs": False, "environment": {}, "extra_pip_args": [], "isolated": True, "pip_data_exclude": [], "python_interpreter": "python3", "python_interpreter_target": interpreter, "quiet": True, "repo": "pip", "repo_prefix": "pip_", "timeout": 600}
_annotations = {}
-def _clean_name(name):
- return name.replace("-", "_").replace(".", "_").lower()
-
def requirement(name):
- return "@pip_" + _clean_name(name) + "//:pkg"
+ return "@pip//{}:{}".format(pip_utils.normalize_name(name), "pkg")
def whl_requirement(name):
- return "@pip_" + _clean_name(name) + "//:whl"
+ return "@pip//{}:{}".format(pip_utils.normalize_name(name), "whl")
def data_requirement(name):
- return "@pip_" + _clean_name(name) + "//:data"
+ return "@pip//{}:{}".format(pip_utils.normalize_name(name), "data")
def dist_info_requirement(name):
- return "@pip_" + _clean_name(name) + "//:dist_info"
+ return "@pip//{}:{}".format(pip_utils.normalize_name(name), "dist_info")
def entry_point(pkg, script = None):
if not script:
script = pkg
- return "@pip_" + _clean_name(pkg) + "//:rules_python_wheel_entry_point_" + script
+ return "@pip_" + pip_utils.normalize_name(pkg) + "//:rules_python_wheel_entry_point_" + script
def _get_annotation(requirement):
# This expects to parse `setuptools==58.2.0 --hash=sha256:2551203ae6955b9876741a26ab3e767bb3242dafe86a32a749ea0d78b6792f11`
@@ -44,12 +44,42 @@ def _get_annotation(requirement):
return _annotations.get(name)
def install_deps(**whl_library_kwargs):
+ """Repository rule macro. Install dependencies from `pip_parse`.
+
+ Args:
+ **whl_library_kwargs: Additional arguments which will flow to underlying
+ `whl_library` calls. See pip_repository.bzl for details.
+ """
+
+ # Set up the requirement groups
+ all_requirement_groups = {}
+
+ requirement_group_mapping = {
+ requirement: group_name
+ for group_name, group_requirements in all_requirement_groups.items()
+ for requirement in group_requirements
+ }
+
+ group_repo = "pip__groups"
+ group_library(
+ name = group_repo,
+ repo_prefix = "pip_",
+ groups = all_requirement_groups,
+ )
+
+ # Install wheels which may be participants in a group
whl_config = dict(_config)
whl_config.update(whl_library_kwargs)
+
for name, requirement in _packages:
+ group_name = requirement_group_mapping.get(name.replace("pip_", ""))
+ group_deps = all_requirement_groups.get(group_name, [])
+
whl_library(
name = name,
requirement = requirement,
+ group_name = group_name,
+ group_deps = group_deps,
annotation = _get_annotation(requirement),
**whl_config
)
diff --git a/examples/pip_parse_vendored/requirements.in b/examples/pip_parse_vendored/requirements.in
index f229360..7ec4233 100644
--- a/examples/pip_parse_vendored/requirements.in
+++ b/examples/pip_parse_vendored/requirements.in
@@ -1 +1,2 @@
requests
+certifi>=2023.7.22 # https://security.snyk.io/vuln/SNYK-PYTHON-CERTIFI-5805047
diff --git a/examples/pip_parse_vendored/requirements.txt b/examples/pip_parse_vendored/requirements.txt
index ff1a363..75b45a1 100644
--- a/examples/pip_parse_vendored/requirements.txt
+++ b/examples/pip_parse_vendored/requirements.txt
@@ -4,10 +4,12 @@
#
# bazel run //:requirements.update
#
-certifi==2022.12.7 \
- --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
- --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
- # via requests
+certifi==2023.7.22 \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+ # via
+ # -r requirements.in
+ # requests
charset-normalizer==2.1.1 \
--hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
--hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
diff --git a/examples/pip_repository_annotations/.bazelrc b/examples/pip_repository_annotations/.bazelrc
index 9e7ef37..9ce0b72 100644
--- a/examples/pip_repository_annotations/.bazelrc
+++ b/examples/pip_repository_annotations/.bazelrc
@@ -1,2 +1,6 @@
# https://docs.bazel.build/versions/main/best-practices.html#using-the-bazelrc-file
try-import %workspace%/user.bazelrc
+
+# This example is WORKSPACE specific. The equivalent functionality
+# is in examples/bzlmod as the `whl_mods` feature.
+build --experimental_enable_bzlmod=false
diff --git a/examples/pip_repository_annotations/BUILD.bazel b/examples/pip_repository_annotations/BUILD.bazel
index 84089f7..bdf9df1 100644
--- a/examples/pip_repository_annotations/BUILD.bazel
+++ b/examples/pip_repository_annotations/BUILD.bazel
@@ -1,4 +1,3 @@
-load("@pip_installed//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_test")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
@@ -10,35 +9,20 @@ exports_files(
# This rule adds a convenient way to update the requirements file.
compile_pip_requirements(
name = "requirements",
- extra_args = ["--allow-unsafe"],
+ src = "requirements.in",
)
py_test(
name = "pip_parse_annotations_test",
srcs = ["pip_repository_annotations_test.py"],
env = {
- "REQUESTS_PKG_DIR": "pip_parsed_requests",
- "WHEEL_PKG_DIR": "pip_parsed_wheel",
+ "REQUESTS_PKG_DIR": "pip_requests",
+ "WHEEL_PKG_DIR": "pip_wheel",
},
main = "pip_repository_annotations_test.py",
deps = [
- "@pip_parsed_requests//:pkg",
- "@pip_parsed_wheel//:pkg",
- "@rules_python//python/runfiles",
- ],
-)
-
-py_test(
- name = "pip_install_annotations_test",
- srcs = ["pip_repository_annotations_test.py"],
- env = {
- "REQUESTS_PKG_DIR": "pip_installed_requests",
- "WHEEL_PKG_DIR": "pip_installed_wheel",
- },
- main = "pip_repository_annotations_test.py",
- deps = [
- requirement("wheel"),
- requirement("requests"),
+ "@pip_requests//:pkg",
+ "@pip_wheel//:pkg",
"@rules_python//python/runfiles",
],
)
diff --git a/examples/pip_repository_annotations/WORKSPACE b/examples/pip_repository_annotations/WORKSPACE
index 3deea03..3535055 100644
--- a/examples/pip_repository_annotations/WORKSPACE
+++ b/examples/pip_repository_annotations/WORKSPACE
@@ -15,7 +15,7 @@ python_register_toolchains(
)
load("@python39//:defs.bzl", "interpreter")
-load("@rules_python//python:pip.bzl", "package_annotation", "pip_install", "pip_parse")
+load("@rules_python//python:pip.bzl", "package_annotation", "pip_parse")
# Here we can see an example of annotations being applied to an arbitrary
# package. For details on `package_annotation` and it's uses, see the
@@ -52,24 +52,12 @@ write_file(
# For a more thorough example of `pip_parse`. See `@rules_python//examples/pip_parse`
pip_parse(
- name = "pip_parsed",
+ name = "pip",
annotations = ANNOTATIONS,
python_interpreter_target = interpreter,
requirements_lock = "//:requirements.txt",
)
-load("@pip_parsed//:requirements.bzl", install_pip_parse_deps = "install_deps")
+load("@pip//:requirements.bzl", "install_deps")
-install_pip_parse_deps()
-
-# For a more thorough example of `pip_install`. See `@rules_python//examples/pip_install`
-pip_install(
- name = "pip_installed",
- annotations = ANNOTATIONS,
- python_interpreter_target = interpreter,
- requirements = "//:requirements.txt",
-)
-
-load("@pip_installed//:requirements.bzl", install_pip_install_deps = "install_deps")
-
-install_pip_install_deps()
+install_deps()
diff --git a/examples/pip_repository_annotations/requirements.in b/examples/pip_repository_annotations/requirements.in
index fd3f75c..c9afafc 100644
--- a/examples/pip_repository_annotations/requirements.in
+++ b/examples/pip_repository_annotations/requirements.in
@@ -1,6 +1,7 @@
# This flag allows for regression testing requirements arguments in
# `pip_repository` rules.
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
+certifi>=2023.7.22 # https://security.snyk.io/vuln/SNYK-PYTHON-CERTIFI-5805047
wheel
requests[security]>=2.8.1
diff --git a/examples/pip_repository_annotations/requirements.txt b/examples/pip_repository_annotations/requirements.txt
index 9fde0a9..290d93e 100644
--- a/examples/pip_repository_annotations/requirements.txt
+++ b/examples/pip_repository_annotations/requirements.txt
@@ -4,12 +4,14 @@
#
# bazel run //:requirements.update
#
---extra-index-url https://pypi.python.org/simple/
+--extra-index-url https://pypi.org/simple/
-certifi==2022.12.7 \
- --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
- --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
- # via requests
+certifi==2023.7.22 \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+ # via
+ # -r requirements.in
+ # requests
charset-normalizer==2.1.1 \
--hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
--hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
@@ -22,9 +24,9 @@ requests[security]==2.28.1 \
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
# via -r requirements.in
-urllib3==1.26.13 \
- --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \
- --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
wheel==0.38.4 \
--hash=sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac \
diff --git a/examples/py_proto_library/.bazelrc b/examples/py_proto_library/.bazelrc
index e69de29..ef0e530 100644
--- a/examples/py_proto_library/.bazelrc
+++ b/examples/py_proto_library/.bazelrc
@@ -0,0 +1,2 @@
+# The equivalent bzlmod behavior is covered by examples/bzlmod/py_proto_library
+common --noenable_bzlmod
diff --git a/examples/py_proto_library/BUILD.bazel b/examples/py_proto_library/BUILD.bazel
index 7a18a5e..0158aa2 100644
--- a/examples/py_proto_library/BUILD.bazel
+++ b/examples/py_proto_library/BUILD.bazel
@@ -1,22 +1,18 @@
-load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_python//python:defs.bzl", "py_test")
-load("@rules_python//python:proto.bzl", "py_proto_library")
-
-py_proto_library(
- name = "pricetag_proto_py_pb2",
- deps = [":pricetag_proto"],
-)
-
-proto_library(
- name = "pricetag_proto",
- srcs = ["pricetag.proto"],
-)
py_test(
name = "pricetag_test",
srcs = ["test.py"],
main = "test.py",
deps = [
- ":pricetag_proto_py_pb2",
+ "//example.com/proto:pricetag_proto_py_pb2",
+ ],
+)
+
+py_test(
+ name = "message_test",
+ srcs = ["message_test.py"],
+ deps = [
+ "//example.com/another_proto:message_proto_py_pb2",
],
)
diff --git a/examples/py_proto_library/MODULE.bazel b/examples/py_proto_library/MODULE.bazel
deleted file mode 100644
index feb938d..0000000
--- a/examples/py_proto_library/MODULE.bazel
+++ /dev/null
@@ -1,23 +0,0 @@
-module(
- name = "rules_python_py_proto_library_example",
- version = "0.0.0",
- compatibility_level = 1,
-)
-
-bazel_dep(name = "rules_python", version = "0.17.3")
-
-# The following local_path_override is only needed to run this example as part of our CI.
-local_path_override(
- module_name = "rules_python",
- path = "../..",
-)
-
-python = use_extension("@rules_python//python/extensions:python.bzl", "python")
-python.toolchain(
- configure_coverage_tool = True,
- python_version = "3.9",
-)
-use_repo(python, "python_3_9")
-
-# We are using rules_proto to define rules_proto targets to be consumed by py_proto_library.
-bazel_dep(name = "rules_proto", version = "5.3.0-21.7")
diff --git a/examples/py_proto_library/example.com/another_proto/BUILD.bazel b/examples/py_proto_library/example.com/another_proto/BUILD.bazel
new file mode 100644
index 0000000..dd58265
--- /dev/null
+++ b/examples/py_proto_library/example.com/another_proto/BUILD.bazel
@@ -0,0 +1,16 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@rules_python//python:proto.bzl", "py_proto_library")
+
+py_proto_library(
+ name = "message_proto_py_pb2",
+ visibility = ["//visibility:public"],
+ deps = [":message_proto"],
+)
+
+proto_library(
+ name = "message_proto",
+ srcs = ["message.proto"],
+ # https://bazel.build/reference/be/protocol-buffer#proto_library.strip_import_prefix
+ strip_import_prefix = "/example.com",
+ deps = ["//example.com/proto:pricetag_proto"],
+)
diff --git a/examples/py_proto_library/example.com/another_proto/message.proto b/examples/py_proto_library/example.com/another_proto/message.proto
new file mode 100644
index 0000000..6e7dcc5
--- /dev/null
+++ b/examples/py_proto_library/example.com/another_proto/message.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+
+package rules_python;
+
+import "proto/pricetag.proto";
+
+message TestMessage {
+ uint32 index = 1;
+ PriceTag pricetag = 2;
+}
diff --git a/examples/py_proto_library/example.com/proto/BUILD.bazel b/examples/py_proto_library/example.com/proto/BUILD.bazel
new file mode 100644
index 0000000..dc91162
--- /dev/null
+++ b/examples/py_proto_library/example.com/proto/BUILD.bazel
@@ -0,0 +1,17 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@rules_python//python:proto.bzl", "py_proto_library")
+
+py_proto_library(
+ name = "pricetag_proto_py_pb2",
+ visibility = ["//visibility:public"],
+ deps = [":pricetag_proto"],
+)
+
+proto_library(
+ name = "pricetag_proto",
+ srcs = ["pricetag.proto"],
+ # https://bazel.build/reference/be/protocol-buffer#proto_library.strip_import_prefix
+ strip_import_prefix = "/example.com",
+ visibility = ["//visibility:public"],
+ deps = ["@com_google_protobuf//:any_proto"],
+)
diff --git a/examples/py_proto_library/example.com/proto/pricetag.proto b/examples/py_proto_library/example.com/proto/pricetag.proto
new file mode 100644
index 0000000..3fa68de
--- /dev/null
+++ b/examples/py_proto_library/example.com/proto/pricetag.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+
+import "google/protobuf/any.proto";
+
+package rules_python;
+
+message PriceTag {
+ string name = 2;
+ double cost = 1;
+ google.protobuf.Any metadata = 3;
+}
diff --git a/examples/py_proto_library/message_test.py b/examples/py_proto_library/message_test.py
new file mode 100644
index 0000000..3aee1ee
--- /dev/null
+++ b/examples/py_proto_library/message_test.py
@@ -0,0 +1,15 @@
+import sys
+import unittest
+
+from another_proto import message_pb2
+
+class TestCase(unittest.TestCase):
+ def test_message(self):
+ got = message_pb2.TestMessage(
+ index = 5,
+ )
+ self.assertIsNotNone(got)
+
+
+if __name__ == "__main__":
+ sys.exit(unittest.main())
diff --git a/examples/py_proto_library/test.py b/examples/py_proto_library/test.py
index 9f09702..24ab8dd 100644
--- a/examples/py_proto_library/test.py
+++ b/examples/py_proto_library/test.py
@@ -1,7 +1,7 @@
-import sys
+import json
import unittest
-import pricetag_pb2
+from proto import pricetag_pb2
class TestCase(unittest.TestCase):
@@ -10,6 +10,10 @@ class TestCase(unittest.TestCase):
name="dollar",
cost=5.00,
)
+
+ metadata = {"description": "some text..."}
+ got.metadata.value = json.dumps(metadata).encode("utf-8")
+
self.assertIsNotNone(got)
diff --git a/examples/wheel/BUILD.bazel b/examples/wheel/BUILD.bazel
index f56a41b..ab4f3a3 100644
--- a/examples/wheel/BUILD.bazel
+++ b/examples/wheel/BUILD.bazel
@@ -54,6 +54,8 @@ py_wheel(
testonly = True, # Set this to verify the generated .dist target doesn't break things
# Package data. We're building "example_minimal_library-0.0.1-py3-none-any.whl"
distribution = "example_minimal_library",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "py3",
version = "0.0.1",
deps = [
@@ -76,6 +78,8 @@ py_wheel(
testonly = True,
abi = "$(ABI)",
distribution = "example_minimal_library",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "$(PYTHON_TAG)",
toolchains = ["//examples/wheel:make_variable_tags"],
version = "$(VERSION)",
@@ -95,6 +99,8 @@ py_wheel(
name = "minimal_with_py_library_with_stamp",
# Package data. We're building "example_minimal_library-0.0.1-py3-none-any.whl"
distribution = "example_minimal_library{BUILD_USER}",
+ incompatible_normalize_name = False,
+ incompatible_normalize_version = False,
python_tag = "py3",
stamp = 1,
version = "0.1.{BUILD_TIMESTAMP}",
@@ -123,6 +129,8 @@ py_wheel(
name = "minimal_with_py_package",
# Package data. We're building "example_minimal_package-0.0.1-py3-none-any.whl"
distribution = "example_minimal_package",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "py3",
version = "0.0.1",
deps = [":example_pkg"],
@@ -156,6 +164,8 @@ py_wheel(
"//examples/wheel:README.md": "README",
},
homepage = "www.example.com",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
license = "Apache 2.0",
project_urls = {
"Bug Tracker": "www.example.com/issues",
@@ -177,6 +187,8 @@ py_wheel(
entry_points = {
"console_scripts": ["main = foo.bar:baz"],
},
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "py3",
strip_path_prefixes = [
"examples",
@@ -191,6 +203,8 @@ py_wheel(
name = "custom_package_root_multi_prefix",
# Package data. We're building "custom_custom_package_root_multi_prefix-0.0.1-py3-none-any.whl"
distribution = "example_custom_package_root_multi_prefix",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "py3",
strip_path_prefixes = [
"examples/wheel/lib",
@@ -206,6 +220,8 @@ py_wheel(
name = "custom_package_root_multi_prefix_reverse_order",
# Package data. We're building "custom_custom_package_root_multi_prefix_reverse_order-0.0.1-py3-none-any.whl"
distribution = "example_custom_package_root_multi_prefix_reverse_order",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "py3",
strip_path_prefixes = [
"examples/wheel",
@@ -220,6 +236,8 @@ py_wheel(
py_wheel(
name = "python_requires_in_a_package",
distribution = "example_python_requires_in_a_package",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_requires = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
python_tag = "py3",
version = "0.0.1",
@@ -231,6 +249,8 @@ py_wheel(
py_wheel(
name = "use_rule_with_dir_in_outs",
distribution = "use_rule_with_dir_in_outs",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
python_tag = "py3",
version = "0.0.1",
deps = [
@@ -244,6 +264,8 @@ py_wheel(
name = "python_abi3_binary_wheel",
abi = "abi3",
distribution = "example_python_abi3_binary_wheel",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
# these platform strings must line up with test_python_abi3_binary_wheel() in wheel_test.py
platform = select({
":aarch64-apple-darwin": "macosx_11_0_arm64",
@@ -258,16 +280,32 @@ py_wheel(
)
py_wheel(
- name = "filename_escaping",
+ name = "legacy_filename_escaping",
# Per https://www.python.org/dev/peps/pep-0427/#escaping-and-unicode
# runs of non-alphanumeric, non-digit symbols should be replaced with a single underscore.
# Unicode non-ascii letters should *not* be replaced with underscore.
distribution = "file~~name-escaping",
+ incompatible_normalize_name = False,
+ incompatible_normalize_version = False,
python_tag = "py3",
version = "0.0.1-r7",
deps = [":example_pkg"],
)
+py_wheel(
+ name = "filename_escaping",
+ # Per https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
+ # runs of "-", "_" and "." should be replaced with a single underscore.
+ # Unicode non-ascii letters aren't allowed according to
+ # https://packaging.python.org/en/latest/specifications/name-normalization/.
+ distribution = "File--Name-Escaping",
+ incompatible_normalize_name = True,
+ incompatible_normalize_version = True,
+ python_tag = "py3",
+ version = "v0.0.1.RC1+ubuntu-r7",
+ deps = [":example_pkg"],
+)
+
py_test(
name = "wheel_test",
srcs = ["wheel_test.py"],
@@ -277,6 +315,7 @@ py_test(
":custom_package_root_multi_prefix_reverse_order",
":customized",
":filename_escaping",
+ ":legacy_filename_escaping",
":minimal_with_py_library",
":minimal_with_py_library_with_stamp",
":minimal_with_py_package",
@@ -284,4 +323,7 @@ py_test(
":python_requires_in_a_package",
":use_rule_with_dir_in_outs",
],
+ deps = [
+ "//python/runfiles",
+ ],
)
diff --git a/examples/wheel/wheel_test.py b/examples/wheel/wheel_test.py
index f51a0ec..43fbe0c 100644
--- a/examples/wheel/wheel_test.py
+++ b/examples/wheel/wheel_test.py
@@ -12,25 +12,61 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import hashlib
import os
import platform
import subprocess
import unittest
import zipfile
+from python.runfiles import runfiles
+
class WheelTest(unittest.TestCase):
maxDiff = None
+ def setUp(self):
+ super().setUp()
+ self.runfiles = runfiles.Create()
+
+ def _get_path(self, filename):
+ runfiles_path = os.path.join("rules_python/examples/wheel", filename)
+ path = self.runfiles.Rlocation(runfiles_path)
+ # The runfiles API can return None if the path doesn't exist or
+ # can't be resolved.
+ if not path:
+ raise AssertionError(f"Runfiles failed to resolve {runfiles_path}")
+ elif not os.path.exists(path):
+ # A non-None value doesn't mean the file actually exists, though
+ raise AssertionError(
+ f"Path {path} does not exist (from runfiles path {runfiles_path}"
+ )
+ else:
+ return path
+
+ def assertFileSha256Equal(self, filename, want):
+ hash = hashlib.sha256()
+ with open(filename, "rb") as f:
+ while True:
+ buf = f.read(2**20)
+ if not buf:
+ break
+ hash.update(buf)
+ self.assertEqual(want, hash.hexdigest())
+
+ def assertAllEntriesHasReproducibleMetadata(self, zf):
+ for zinfo in zf.infolist():
+ self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0), msg=zinfo.filename)
+ self.assertEqual(zinfo.create_system, 3, msg=zinfo.filename)
+ self.assertEqual(zinfo.external_attr, 0o777 << 16, msg=zinfo.filename)
+ self.assertEqual(
+ zinfo.compress_type, zipfile.ZIP_DEFLATED, msg=zinfo.filename
+ )
+
def test_py_library_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
- "example_minimal_library-0.0.1-py3-none-any.whl",
- )
+ filename = self._get_path("example_minimal_library-0.0.1-py3-none-any.whl")
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -41,16 +77,16 @@ class WheelTest(unittest.TestCase):
"example_minimal_library-0.0.1.dist-info/RECORD",
],
)
+ self.assertFileSha256Equal(
+ filename, "2818e70fdebd148934f41820f8c54d5d7676d783c0d66c7c8af2ee9141e7ddc7"
+ )
def test_py_package_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"example_minimal_package-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -63,16 +99,16 @@ class WheelTest(unittest.TestCase):
"example_minimal_package-0.0.1.dist-info/RECORD",
],
)
+ self.assertFileSha256Equal(
+ filename, "273e27adf9bf90287a42ac911dcece8aa95f2905c37d786725477b26de23627c"
+ )
def test_customized_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"example_customized-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -99,16 +135,16 @@ class WheelTest(unittest.TestCase):
record_contents,
# The entries are guaranteed to be sorted.
b"""\
-example_customized-0.0.1.dist-info/METADATA,sha256=QYQcDJFQSIqan8eiXqL67bqsUfgEAwf2hoK_Lgi1S-0,559
-example_customized-0.0.1.dist-info/NOTICE,sha256=Xpdw-FXET1IRgZ_wTkx1YQfo1-alET0FVf6V1LXO4js,76
-example_customized-0.0.1.dist-info/README,sha256=WmOFwZ3Jga1bHG3JiGRsUheb4UbLffUxyTdHczS27-o,40
-example_customized-0.0.1.dist-info/RECORD,,
-example_customized-0.0.1.dist-info/WHEEL,sha256=sobxWSyDDkdg_rinUth-jxhXHqoNqlmNMJY3aTZn2Us,91
-example_customized-0.0.1.dist-info/entry_points.txt,sha256=pqzpbQ8MMorrJ3Jp0ntmpZcuvfByyqzMXXi2UujuXD0,137
examples/wheel/lib/data.txt,sha256=9vJKEdfLu8bZRArKLroPZJh1XKkK3qFMXiM79MBL2Sg,12
examples/wheel/lib/module_with_data.py,sha256=8s0Khhcqz3yVsBKv2IB5u4l4TMKh7-c_V6p65WVHPms,637
examples/wheel/lib/simple_module.py,sha256=z2hwciab_XPNIBNH8B1Q5fYgnJvQTeYf0ZQJpY8yLLY,637
examples/wheel/main.py,sha256=sgg5iWN_9inYBjm6_Zw27hYdmo-l24fA-2rfphT-IlY,909
+example_customized-0.0.1.dist-info/WHEEL,sha256=sobxWSyDDkdg_rinUth-jxhXHqoNqlmNMJY3aTZn2Us,91
+example_customized-0.0.1.dist-info/METADATA,sha256=QYQcDJFQSIqan8eiXqL67bqsUfgEAwf2hoK_Lgi1S-0,559
+example_customized-0.0.1.dist-info/entry_points.txt,sha256=pqzpbQ8MMorrJ3Jp0ntmpZcuvfByyqzMXXi2UujuXD0,137
+example_customized-0.0.1.dist-info/NOTICE,sha256=Xpdw-FXET1IRgZ_wTkx1YQfo1-alET0FVf6V1LXO4js,76
+example_customized-0.0.1.dist-info/README,sha256=WmOFwZ3Jga1bHG3JiGRsUheb4UbLffUxyTdHczS27-o,40
+example_customized-0.0.1.dist-info/RECORD,,
""",
)
self.assertEqual(
@@ -152,16 +188,16 @@ customized_wheel = examples.wheel.main:main
first = first.main:f
second = second.main:s""",
)
+ self.assertFileSha256Equal(
+ filename, "48eed93258bba0bb366c879b77917d947267d89e7e60005d1766d844fb909118"
+ )
- def test_filename_escaping(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ def test_legacy_filename_escaping(self):
+ filename = self._get_path(
"file_name_escaping-0.0.1_r7-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -190,17 +226,51 @@ Version: 0.0.1-r7
UNKNOWN
""",
)
+ self.assertFileSha256Equal(
+ filename, "ace5fab6458f8c3b4b50801b8e8214288bba786472e81547fced743a67531312"
+ )
+
+ def test_filename_escaping(self):
+ filename = self._get_path(
+ "file_name_escaping-0.0.1rc1+ubuntu.r7-py3-none-any.whl",
+ )
+ with zipfile.ZipFile(filename) as zf:
+ self.assertEqual(
+ zf.namelist(),
+ [
+ "examples/wheel/lib/data.txt",
+ "examples/wheel/lib/module_with_data.py",
+ "examples/wheel/lib/simple_module.py",
+ "examples/wheel/main.py",
+ # PEP calls for replacing only in the archive filename.
+ # Alas setuptools also escapes in the dist-info directory
+ # name, so let's be compatible.
+ "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/WHEEL",
+ "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/METADATA",
+ "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/RECORD",
+ ],
+ )
+ metadata_contents = zf.read(
+ "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/METADATA"
+ )
+ self.assertEqual(
+ metadata_contents,
+ b"""\
+Metadata-Version: 2.1
+Name: File--Name-Escaping
+Version: 0.0.1rc1+ubuntu.r7
+
+UNKNOWN
+""",
+ )
def test_custom_package_root_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"examples_custom_package_root-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -222,17 +292,17 @@ UNKNOWN
# Ensure RECORD files do not have leading forward slashes
for line in record_contents.splitlines():
self.assertFalse(line.startswith("/"))
+ self.assertFileSha256Equal(
+ filename, "16e0345c102c6866fed34999d8de5aed7f351adbf372b27adef3bc15161db65e"
+ )
def test_custom_package_root_multi_prefix_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"example_custom_package_root_multi_prefix-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -253,17 +323,17 @@ UNKNOWN
# Ensure RECORD files do not have leading forward slashes
for line in record_contents.splitlines():
self.assertFalse(line.startswith("/"))
+ self.assertFileSha256Equal(
+ filename, "d2031eb21c69e290db5eac76b0dc026858e9dbdb3da2dc0314e4e9f69eab2e1a"
+ )
def test_custom_package_root_multi_prefix_reverse_order_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"example_custom_package_root_multi_prefix_reverse_order-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -284,16 +354,16 @@ UNKNOWN
# Ensure RECORD files do not have leading forward slashes
for line in record_contents.splitlines():
self.assertFalse(line.startswith("/"))
+ self.assertFileSha256Equal(
+ filename, "a37b90685600ccfa56cc5405d1e9a3729ed21dfb31c76fd356e491e2af989566"
+ )
def test_python_requires_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"example_python_requires_in_a_package-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
metadata_contents = zf.read(
"example_python_requires_in_a_package-0.0.1.dist-info/METADATA"
)
@@ -309,6 +379,9 @@ Version: 0.0.1
UNKNOWN
""",
)
+ self.assertFileSha256Equal(
+ filename, "529afa454113572e6cd91f069cc9cfe5c28369f29cd495fff19d0ecce389d8e4"
+ )
def test_python_abi3_binary_wheel(self):
arch = "amd64"
@@ -321,14 +394,11 @@ UNKNOWN
"Windows": "win",
}
os_string = os_strings[platform.system()]
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
f"example_python_abi3_binary_wheel-0.0.1-cp38-abi3-{os_string}_{arch}.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
metadata_contents = zf.read(
"example_python_abi3_binary_wheel-0.0.1.dist-info/METADATA"
)
@@ -358,15 +428,12 @@ Tag: cp38-abi3-{os_string}_{arch}
)
def test_rule_creates_directory_and_is_included_in_wheel(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
+ filename = self._get_path(
"use_rule_with_dir_in_outs-0.0.1-py3-none-any.whl",
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
self.assertEqual(
zf.namelist(),
[
@@ -377,17 +444,17 @@ Tag: cp38-abi3-{os_string}_{arch}
"use_rule_with_dir_in_outs-0.0.1.dist-info/RECORD",
],
)
+ self.assertFileSha256Equal(
+ filename, "cc9484d527075f07651ca0e7dff4a185c1314020726bcad55fe28d1bba0fec2e"
+ )
def test_rule_expands_workspace_status_keys_in_wheel_metadata(self):
- filename = os.path.join(
- os.environ["TEST_SRCDIR"],
- "rules_python",
- "examples",
- "wheel",
- "example_minimal_library_BUILD_USER_-0.1._BUILD_TIMESTAMP_-py3-none-any.whl",
+ filename = self._get_path(
+ "example_minimal_library_BUILD_USER_-0.1._BUILD_TIMESTAMP_-py3-none-any.whl"
)
with zipfile.ZipFile(filename) as zf:
+ self.assertAllEntriesHasReproducibleMetadata(zf)
metadata_file = None
for f in zf.namelist():
self.assertNotIn("_BUILD_TIMESTAMP_", f)
diff --git a/gazelle/.bazelrc b/gazelle/.bazelrc
index f48d0a9..7a67d3e 100644
--- a/gazelle/.bazelrc
+++ b/gazelle/.bazelrc
@@ -11,3 +11,11 @@ build --incompatible_default_to_explicit_init_py
# Windows makes use of runfiles for some rules
build --enable_runfiles
startup --windows_enable_symlinks
+
+# Do NOT implicitly create empty __init__.py files in the runfiles tree.
+# By default, these are created in every directory containing Python source code
+# or shared libraries, and every parent directory of those directories,
+# excluding the repo root directory. With this flag set, we are responsible for
+# creating (possibly empty) __init__.py files and adding them to the srcs of
+# Python targets as required.
+build --incompatible_default_to_explicit_init_py
diff --git a/gazelle/BUILD.bazel b/gazelle/BUILD.bazel
index 6016145..e00c74a 100644
--- a/gazelle/BUILD.bazel
+++ b/gazelle/BUILD.bazel
@@ -1,10 +1,18 @@
-load("@bazel_gazelle//:def.bzl", "gazelle")
+load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle", "gazelle_binary")
# Gazelle configuration options.
# See https://github.com/bazelbuild/bazel-gazelle#running-gazelle-with-bazel
# gazelle:prefix github.com/bazelbuild/rules_python/gazelle
# gazelle:exclude bazel-out
-gazelle(name = "gazelle")
+gazelle(
+ name = "gazelle",
+ gazelle = ":gazelle_binary",
+)
+
+gazelle_binary(
+ name = "gazelle_binary",
+ languages = DEFAULT_LANGUAGES + ["//python"],
+)
gazelle(
name = "gazelle_update_repos",
@@ -20,6 +28,7 @@ filegroup(
name = "distribution",
srcs = [
":BUILD.bazel",
+ ":MODULE.bazel",
":README.md",
":WORKSPACE",
":def.bzl",
diff --git a/gazelle/MODULE.bazel b/gazelle/MODULE.bazel
index ae94a5f..8c6ad19 100644
--- a/gazelle/MODULE.bazel
+++ b/gazelle/MODULE.bazel
@@ -5,8 +5,8 @@ module(
)
bazel_dep(name = "rules_python", version = "0.18.0")
-bazel_dep(name = "rules_go", version = "0.38.1", repo_name = "io_bazel_rules_go")
-bazel_dep(name = "gazelle", version = "0.31.0", repo_name = "bazel_gazelle")
+bazel_dep(name = "rules_go", version = "0.41.0", repo_name = "io_bazel_rules_go")
+bazel_dep(name = "gazelle", version = "0.33.0", repo_name = "bazel_gazelle")
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
diff --git a/gazelle/README.md b/gazelle/README.md
index ba8520d..a9a69cc 100644
--- a/gazelle/README.md
+++ b/gazelle/README.md
@@ -7,7 +7,9 @@ Gazelle may be run by Bazel using the gazelle rule, or it may be installed and r
This directory contains a plugin for
[Gazelle](https://github.com/bazelbuild/bazel-gazelle)
-that generates BUILD files content for Python code.
+that generates BUILD files content for Python code. When Gazelle is run as a command line tool with this plugin, it embeds a Python interpreter resolved during the plugin build.
+The behavior of the plugin is slightly different with different version of the interpreter as the Python `stdlib` changes with every minor version release.
+Distributors of Gazelle binaries should, therefore, build a Gazelle binary for each OS+CPU architecture+Minor Python version combination they are targeting.
The following instructions are for when you use [bzlmod](https://docs.bazel.build/versions/5.0.0/bzlmod.html).
Please refer to older documentation that includes instructions on how to use Gazelle
@@ -64,9 +66,6 @@ pip = use_extension("@rules_python//python:extensions.bzl", "pip")
# 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",
)
@@ -110,15 +109,12 @@ modules_mapping(
gazelle_python_manifest(
name = "gazelle_python_manifest",
modules_mapping = ":modules_map",
- # This is what we called our `pip_install` rule, where third-party
+ # This is what we called our `pip_parse` rule, where third-party
# python libraries are loaded in BUILD files.
pip_repository_name = "pip",
# 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,
)
```
@@ -128,7 +124,6 @@ with the rules_python extension included. This typically goes in your root
```starlark
load("@bazel_gazelle//:def.bzl", "gazelle")
-load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
# Our gazelle target points to the python gazelle binary.
# This is the simple case where we only need one language supported.
@@ -137,7 +132,6 @@ load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
# See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example
gazelle(
name = "gazelle",
- data = GAZELLE_PYTHON_RUNTIME_DEPS,
gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary",
)
```
@@ -189,9 +183,11 @@ Python-specific directives are as follows:
| `# gazelle:python_validate_import_statements`| `true` |
| Controls whether the Python import statements should be validated. Can be "true" or "false" | |
| `# gazelle:python_generation_mode`| `package` |
-| Controls the target generation mode. Can be "package" or "project" | |
+| Controls the target generation mode. Can be "file", "package", or "project" | |
+| `# gazelle:python_generation_mode_per_file_include_init`| `package` |
+| Controls whether `__init__.py` files are included as srcs in each generated target when target generation mode is "file". Can be "true", or "false" | |
| `# gazelle:python_library_naming_convention`| `$package_name$` |
-| Controls the `py_library` naming convention. It interpolates $package_name$ with the Bazel package name. E.g. if the Bazel package name is `foo`, setting this to `$package_name$_my_lib` would result in a generated target named `foo_my_lib`. | |
+| Controls the `py_library` naming convention. It interpolates \$package_name\$ with the Bazel package name. E.g. if the Bazel package name is `foo`, setting this to `$package_name$_my_lib` would result in a generated target named `foo_my_lib`. | |
| `# gazelle:python_binary_naming_convention` | `$package_name$_bin` |
| Controls the `py_binary` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:python_test_naming_convention` | `$package_name$_test` |
@@ -206,11 +202,15 @@ Python source files are those ending in `.py` but not ending in `_test.py`.
First, we look for the nearest ancestor BUILD file starting from the folder
containing the Python source file.
-If there is no `py_library` in this BUILD file, one is created, using the
-package name as the target's name. This makes it the default target in the
-package.
+In package generation mode, if there is no `py_library` in this BUILD file, one
+is created using the package name as the target's name. This makes it the
+default target in the package. Next, all source files are collected into the
+`srcs` of the `py_library`.
-Next, all source files are collected into the `srcs` of the `py_library`.
+In project generation mode, all source files in subdirectories (that don't have
+BUILD files) are also collected.
+
+In file generation mode, each file is given its own target.
Finally, the `import` statements in the source files are parsed, and
dependencies are added to the `deps` attribute.
@@ -220,7 +220,7 @@ dependencies are added to the `deps` attribute.
A `py_test` target is added to the BUILD file when gazelle encounters
a file named `__test__.py`.
Often, Python unit test files are named with the suffix `_test`.
-For example, if we had a folder that is a package named "foo" we could have a Python file named `foo_test.py`
+For example, if we had a folder that is a package named "foo" we could have a Python file named `foo_test.py`
and gazelle would create a `py_test` block for the file.
The following is an example of a `py_test` target that gazelle would add when
@@ -236,28 +236,35 @@ py_test(
```
You can control the naming convention for test targets by adding a gazelle directive named
-`# gazelle:python_test_naming_convention`. See the instructions in the section above that
+`# gazelle:python_test_naming_convention`. See the instructions in the section above that
covers directives.
### Binaries
When a `__main__.py` file is encountered, this indicates the entry point
-of a Python program.
+of a Python program. A `py_binary` target will be created, named `[package]_bin`.
+
+When no such entry point exists, Gazelle will look for a line like this in the top level in every module:
+
+```python
+if __name == "__main__":
+```
-A `py_binary` target will be created, named `[package]_bin`.
+Gazelle will create `py_binary` target will be created for every module with such line, with the target name
+being the same as module name.
## Developer Notes
-Gazelle extensions are written in Go. This gazelle plugin is a hybrid, as it uses Go to execute a
-Python interpreter as a subprocess to parse Python source files.
-See the gazelle documentation https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.md
+Gazelle extensions are written in Go. This gazelle plugin is a hybrid, as it uses Go to execute a
+Python interpreter as a subprocess to parse Python source files.
+See the gazelle documentation https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.md
for more information on extending Gazelle.
-If you add new Go dependencies to the plugin source code, you need to "tidy" the go.mod file.
-After changing that file, run `go mod tidy` or `bazel run @go_sdk//:bin/go -- mod tidy`
-to update the go.mod and go.sum files. Then run `bazel run //:update_go_deps` to have gazelle
-add the new dependenies to the deps.bzl file. The deps.bzl file is used as defined in our /WORKSPACE
+If you add new Go dependencies to the plugin source code, you need to "tidy" the go.mod file.
+After changing that file, run `go mod tidy` or `bazel run @go_sdk//:bin/go -- mod tidy`
+to update the go.mod and go.sum files. Then run `bazel run //:update_go_deps` to have gazelle
+add the new dependenies to the deps.bzl file. The deps.bzl file is used as defined in our /WORKSPACE
to include the external repos Bazel loads Go dependencies from.
-Then after editing Go code, run `bazel run //:gazelle` to generate/update the rules in the
+Then after editing Go code, run `bazel run //:gazelle` to generate/update the rules in the
BUILD.bazel files in our repo.
diff --git a/gazelle/WORKSPACE b/gazelle/WORKSPACE
index eef16e9..df2883f 100644
--- a/gazelle/WORKSPACE
+++ b/gazelle/WORKSPACE
@@ -4,10 +4,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
- sha256 = "099a9fb96a376ccbbb7d291ed4ecbdfd42f6bc822ab77ae6f1b5cb9e914e94fa",
+ sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
- "https://github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
+ "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
],
)
@@ -34,11 +34,13 @@ local_repository(
path = "..",
)
-load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
+
+py_repositories()
python_register_toolchains(
- name = "python39",
- python_version = "3.9",
+ name = "python_3_11",
+ python_version = "3.11",
)
load("//:deps.bzl", _py_gazelle_deps = "gazelle_deps")
diff --git a/gazelle/def.bzl b/gazelle/def.bzl
index 80b1157..084b5a4 100644
--- a/gazelle/def.bzl
+++ b/gazelle/def.bzl
@@ -16,6 +16,4 @@
"""
GAZELLE_PYTHON_RUNTIME_DEPS = [
- "@rules_python_gazelle_plugin//python:parse",
- "@rules_python_gazelle_plugin//python:std_modules",
]
diff --git a/gazelle/go.mod b/gazelle/go.mod
index 1d1cee7..6789aa1 100644
--- a/gazelle/go.mod
+++ b/gazelle/go.mod
@@ -5,7 +5,7 @@ go 1.19
require (
github.com/bazelbuild/bazel-gazelle v0.31.1
github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d
- github.com/bazelbuild/rules_go v0.39.1
+ github.com/bazelbuild/rules_go v0.41.0
github.com/bmatcuk/doublestar v1.3.4
github.com/emirpasic/gods v1.18.1
github.com/ghodss/yaml v1.0.0
diff --git a/gazelle/go.sum b/gazelle/go.sum
index ba2c8bf..5617f9b 100644
--- a/gazelle/go.sum
+++ b/gazelle/go.sum
@@ -4,8 +4,8 @@ github.com/bazelbuild/bazel-gazelle v0.31.1 h1:ROyUyUHzoEdvoOs1e0haxJx1l5EjZX6AO
github.com/bazelbuild/bazel-gazelle v0.31.1/go.mod h1:Ul0pqz50f5wxz0QNzsZ+mrEu4AVAVJZEB5xLnHgIG9c=
github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d h1:Fl1FfItZp34QIQmmDTbZXHB5XA6JfbNNfH7tRRGWvQo=
github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d/go.mod h1:689QdV3hBP7Vo9dJMmzhoYIyo/9iMhEmHkJcnaPRCbo=
-github.com/bazelbuild/rules_go v0.39.1 h1:wkJLUDx59dntWMghuL8++GteoU1To6sRoKJXuyFtmf8=
-github.com/bazelbuild/rules_go v0.39.1/go.mod h1:TMHmtfpvyfsxaqfL9WnahCsXMWDMICTw7XeK9yVb+YU=
+github.com/bazelbuild/rules_go v0.41.0 h1:JzlRxsFNhlX+g4drDRPhIaU5H5LnI978wdMJ0vK4I+k=
+github.com/bazelbuild/rules_go v0.41.0/go.mod h1:TMHmtfpvyfsxaqfL9WnahCsXMWDMICTw7XeK9yVb+YU=
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
diff --git a/gazelle/manifest/defs.bzl b/gazelle/manifest/defs.bzl
index f1266a0..f1a16c4 100644
--- a/gazelle/manifest/defs.bzl
+++ b/gazelle/manifest/defs.bzl
@@ -25,7 +25,8 @@ def gazelle_python_manifest(
pip_repository_name = "",
pip_deps_repository_name = "",
manifest = ":gazelle_python.yaml",
- use_pip_repository_aliases = False):
+ use_pip_repository_aliases = None,
+ **kwargs):
"""A macro for defining the updating and testing targets for the Gazelle manifest file.
Args:
@@ -35,10 +36,12 @@ def gazelle_python_manifest(
the manifest generator.
pip_repository_name: the name of the pip_install or pip_repository target.
use_pip_repository_aliases: boolean flag to enable using user-friendly
- python package aliases.
+ python package aliases. Defaults to True.
pip_deps_repository_name: deprecated - the old pip_install target name.
modules_mapping: the target for the generated modules_mapping.json file.
manifest: the target for the Gazelle manifest file.
+ **kwargs: other bazel attributes passed to the target target generated by
+ this macro.
"""
if pip_deps_repository_name != "":
# buildifier: disable=print
@@ -82,11 +85,23 @@ def gazelle_python_manifest(
update_target_label,
]
- if use_pip_repository_aliases:
+ # TODO @aignas 2023-10-31: When removing this code, cleanup the
+ # code in gazelle to only work with aliased targets.
+ if use_pip_repository_aliases == None:
+ update_args += [
+ "--omit-pip-repository-aliases-setting",
+ "true",
+ ]
+ elif use_pip_repository_aliases:
update_args += [
"--use-pip-repository-aliases",
"true",
]
+ else:
+ update_args += [
+ "--use-pip-repository-aliases",
+ "false",
+ ]
go_binary(
name = update_target,
@@ -102,6 +117,14 @@ def gazelle_python_manifest(
tags = ["manual"],
)
+ attrs = {
+ "env": {
+ "_TEST_MANIFEST": "$(rootpath {})".format(manifest),
+ "_TEST_MANIFEST_GENERATOR_HASH": "$(rootpath {})".format(manifest_generator_hash),
+ "_TEST_REQUIREMENTS": "$(rootpath {})".format(requirements),
+ },
+ "size": "small",
+ }
go_test(
name = "{}.test".format(name),
srcs = [Label("//manifest/test:test.go")],
@@ -110,14 +133,10 @@ def gazelle_python_manifest(
requirements,
manifest_generator_hash,
],
- env = {
- "_TEST_MANIFEST": "$(rootpath {})".format(manifest),
- "_TEST_MANIFEST_GENERATOR_HASH": "$(rootpath {})".format(manifest_generator_hash),
- "_TEST_REQUIREMENTS": "$(rootpath {})".format(requirements),
- },
rundir = ".",
deps = [Label("//manifest")],
- size = "small",
+ # kwargs could contain test-specific attributes like size or timeout
+ **dict(attrs, **kwargs)
)
native.filegroup(
diff --git a/gazelle/manifest/generate/generate.go b/gazelle/manifest/generate/generate.go
index 1f56e63..006b15e 100644
--- a/gazelle/manifest/generate/generate.go
+++ b/gazelle/manifest/generate/generate.go
@@ -43,6 +43,7 @@ func main() {
requirementsPath string
pipRepositoryName string
usePipRepositoryAliases bool
+ omitUsePipRepositoryAliases bool
modulesMappingPath string
outputPath string
updateTarget string
@@ -66,8 +67,13 @@ func main() {
flag.BoolVar(
&usePipRepositoryAliases,
"use-pip-repository-aliases",
- false,
+ true,
"Whether to use the pip-repository aliases, which are generated when passing 'incompatible_generate_aliases = True'.")
+ flag.BoolVar(
+ &omitUsePipRepositoryAliases,
+ "omit-pip-repository-aliases-setting",
+ false,
+ "Whether to omit use-pip-repository-aliases flag serialization into the manifest.")
flag.StringVar(
&modulesMappingPath,
"modules-mapping",
@@ -107,13 +113,19 @@ func main() {
}
header := generateHeader(updateTarget)
+ repository := manifest.PipRepository{
+ Name: pipRepositoryName,
+ }
+
+ if omitUsePipRepositoryAliases {
+ repository.UsePipRepositoryAliases = nil
+ } else {
+ repository.UsePipRepositoryAliases = &usePipRepositoryAliases
+ }
manifestFile := manifest.NewFile(&manifest.Manifest{
ModulesMapping: modulesMapping,
- PipRepository: &manifest.PipRepository{
- Name: pipRepositoryName,
- UsePipRepositoryAliases: usePipRepositoryAliases,
- },
+ PipRepository: &repository,
})
if err := writeOutput(
outputPath,
diff --git a/gazelle/manifest/manifest.go b/gazelle/manifest/manifest.go
index c49951d..55adef0 100644
--- a/gazelle/manifest/manifest.go
+++ b/gazelle/manifest/manifest.go
@@ -133,18 +133,18 @@ type Manifest struct {
// ModulesMapping is the mapping from importable modules to which Python
// wheel name provides these modules.
ModulesMapping ModulesMapping `yaml:"modules_mapping"`
- // PipDepsRepositoryName is the name of the pip_install repository target.
+ // PipDepsRepositoryName is the name of the pip_parse repository target.
// DEPRECATED
PipDepsRepositoryName string `yaml:"pip_deps_repository_name,omitempty"`
- // PipRepository contains the information for pip_install or pip_repository
+ // PipRepository contains the information for pip_parse or pip_repository
// target.
PipRepository *PipRepository `yaml:"pip_repository,omitempty"`
}
type PipRepository struct {
- // The name of the pip_install or pip_repository target.
+ // The name of the pip_parse or pip_repository target.
Name string
// UsePipRepositoryAliases allows to use aliases generated pip_repository
// when passing incompatible_generate_aliases = True.
- UsePipRepositoryAliases bool `yaml:"use_pip_repository_aliases,omitempty"`
+ UsePipRepositoryAliases *bool `yaml:"use_pip_repository_aliases,omitempty"`
}
diff --git a/gazelle/modules_mapping/BUILD.bazel b/gazelle/modules_mapping/BUILD.bazel
index 1855551..d78b1fb 100644
--- a/gazelle/modules_mapping/BUILD.bazel
+++ b/gazelle/modules_mapping/BUILD.bazel
@@ -1,5 +1,7 @@
load("@rules_python//python:defs.bzl", "py_binary")
+# gazelle:exclude *.py
+
py_binary(
name = "generator",
srcs = ["generator.py"],
diff --git a/gazelle/modules_mapping/def.bzl b/gazelle/modules_mapping/def.bzl
index 54fc8ad..4da6267 100644
--- a/gazelle/modules_mapping/def.bzl
+++ b/gazelle/modules_mapping/def.bzl
@@ -26,11 +26,15 @@ module name doesn't match the wheel distribution name.
def _modules_mapping_impl(ctx):
modules_mapping = ctx.actions.declare_file(ctx.attr.modules_mapping_name)
args = ctx.actions.args()
+ all_wheels = depset(
+ [whl for whl in ctx.files.wheels],
+ transitive = [dep[DefaultInfo].files for dep in ctx.attr.wheels] + [dep[DefaultInfo].data_runfiles.files for dep in ctx.attr.wheels],
+ )
args.add("--output_file", modules_mapping.path)
args.add_all("--exclude_patterns", ctx.attr.exclude_patterns)
- args.add_all("--wheels", [whl.path for whl in ctx.files.wheels])
+ args.add_all("--wheels", [whl.path for whl in all_wheels.to_list()])
ctx.actions.run(
- inputs = ctx.files.wheels,
+ inputs = all_wheels.to_list(),
outputs = [modules_mapping],
executable = ctx.executable._generator,
arguments = [args],
diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel
index fcfe81b..fd051eb 100644
--- a/gazelle/python/BUILD.bazel
+++ b/gazelle/python/BUILD.bazel
@@ -1,6 +1,7 @@
load("@bazel_gazelle//:def.bzl", "gazelle_binary")
-load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-load("@rules_python//python:defs.bzl", "py_binary")
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@rules_python//python:defs.bzl", "py_binary", "py_test")
+load(":gazelle_test.bzl", "gazelle_test")
go_library(
name = "python",
@@ -16,10 +17,15 @@ go_library(
"std_modules.go",
"target.go",
],
- data = [
- ":parse",
- ":std_modules",
- ],
+ # NOTE @aignas 2023-12-03: currently gazelle does not support embedding
+ # generated files, but helper.zip is generated by a build rule.
+ #
+ # You will get a benign error like when running gazelle locally:
+ # > 8 gazelle: .../rules_python/gazelle/python/lifecycle.go:26:3: pattern helper.zip: matched no files
+ #
+ # See following for more info:
+ # https://github.com/bazelbuild/bazel-gazelle/issues/1513
+ embedsrcs = [":helper.zip"], # keep
importpath = "github.com/bazelbuild/rules_python/gazelle/python",
visibility = ["//visibility:public"],
deps = [
@@ -36,33 +42,58 @@ go_library(
"@com_github_emirpasic_gods//lists/singlylinkedlist",
"@com_github_emirpasic_gods//sets/treeset",
"@com_github_emirpasic_gods//utils",
- "@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
)
py_binary(
- name = "parse",
- srcs = ["parse.py"],
+ name = "helper",
+ srcs = [
+ "__main__.py",
+ "parse.py",
+ "std_modules.py",
+ ],
+ # This is to make sure that the current directory is added to PYTHONPATH
+ imports = ["."],
+ main = "__main__.py",
visibility = ["//visibility:public"],
)
-py_binary(
- name = "std_modules",
- srcs = ["std_modules.py"],
- visibility = ["//visibility:public"],
+py_test(
+ name = "parse_test",
+ srcs = [
+ "parse.py",
+ "parse_test.py",
+ ],
+ imports = ["."],
)
-go_test(
+filegroup(
+ name = "helper.zip",
+ srcs = [":helper"],
+ output_group = "python_zip_file",
+)
+
+# gazelle:exclude testdata/
+
+gazelle_test(
name = "python_test",
srcs = ["python_test.go"],
data = [
":gazelle_binary",
- ":parse",
- ":std_modules",
- ] + glob(["testdata/**"]),
+ ":helper",
+ ],
+ test_dirs = glob(
+ # Use this so that we don't need to manually maintain the list.
+ ["testdata/*"],
+ exclude = ["testdata/*.md"],
+ # The directories aren't inputs themselves; we just want their
+ # names.
+ exclude_directories = 0,
+ ),
deps = [
"@bazel_gazelle//testtools:go_default_library",
"@com_github_ghodss_yaml//:yaml",
+ "@io_bazel_rules_go//go/runfiles:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
)
diff --git a/gazelle/python/__main__.py b/gazelle/python/__main__.py
new file mode 100644
index 0000000..9974c66
--- /dev/null
+++ b/gazelle/python/__main__.py
@@ -0,0 +1,32 @@
+# 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.
+
+# parse.py is a long-living program that communicates over STDIN and STDOUT.
+# STDIN receives parse requests, one per line. It outputs the parsed modules and
+# comments from all the files from each request.
+
+import sys
+
+import parse
+import std_modules
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ sys.exit("Please provide subcommand, either parse or std_modules")
+ if sys.argv[1] == "parse":
+ sys.exit(parse.main(sys.stdin, sys.stdout))
+ elif sys.argv[1] == "std_modules":
+ sys.exit(std_modules.main(sys.stdin, sys.stdout))
+ else:
+ sys.exit("Unknown subcommand: " + sys.argv[1])
diff --git a/gazelle/python/configure.go b/gazelle/python/configure.go
index 32f9ab0..69d2762 100644
--- a/gazelle/python/configure.go
+++ b/gazelle/python/configure.go
@@ -59,6 +59,7 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.IgnoreDependenciesDirective,
pythonconfig.ValidateImportStatementsDirective,
pythonconfig.GenerationMode,
+ pythonconfig.GenerationModePerFileIncludeInit,
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
@@ -137,13 +138,24 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
switch pythonconfig.GenerationModeType(strings.TrimSpace(d.Value)) {
case pythonconfig.GenerationModePackage:
config.SetCoarseGrainedGeneration(false)
+ config.SetPerFileGeneration(false)
+ case pythonconfig.GenerationModeFile:
+ config.SetCoarseGrainedGeneration(false)
+ config.SetPerFileGeneration(true)
case pythonconfig.GenerationModeProject:
config.SetCoarseGrainedGeneration(true)
+ config.SetPerFileGeneration(false)
default:
err := fmt.Errorf("invalid value for directive %q: %s",
pythonconfig.GenerationMode, d.Value)
log.Fatal(err)
}
+ case pythonconfig.GenerationModePerFileIncludeInit:
+ v, err := strconv.ParseBool(strings.TrimSpace(d.Value))
+ if err != nil {
+ log.Fatal(err)
+ }
+ config.SetPerFileGenerationIncludeInit(v)
case pythonconfig.LibraryNamingConvention:
config.SetLibraryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.BinaryNamingConvention:
diff --git a/gazelle/python/gazelle_test.bzl b/gazelle/python/gazelle_test.bzl
new file mode 100644
index 0000000..7c0c242
--- /dev/null
+++ b/gazelle/python/gazelle_test.bzl
@@ -0,0 +1,49 @@
+# 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.
+
+""
+
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+
+def gazelle_test(*, name, test_dirs, **kwargs):
+ """A simple macro to better cache gazelle integration tests
+
+ Args:
+ name (str): The name of the test suite target to be created and
+ the prefix to all of the individual test targets.
+ test_dirs (list[str]): The list of dirs in the 'testdata'
+ directory that we should create separate 'go_test' cases for.
+ Each of them will be prefixed with '{name}'.
+ **kwargs: extra arguments passed to 'go_test'.
+ """
+ tests = []
+
+ data = kwargs.pop("data", [])
+
+ for dir in test_dirs:
+ _, _, basename = dir.rpartition("/")
+
+ test = "{}_{}".format(name, basename)
+ tests.append(test)
+
+ go_test(
+ name = test,
+ data = native.glob(["{}/**".format(dir)]) + data,
+ **kwargs
+ )
+
+ native.test_suite(
+ name = name,
+ tests = tests,
+ )
diff --git a/gazelle/python/generate.go b/gazelle/python/generate.go
index fb41324..95f5396 100644
--- a/gazelle/python/generate.go
+++ b/gazelle/python/generate.go
@@ -20,6 +20,7 @@ import (
"log"
"os"
"path/filepath"
+ "sort"
"strings"
"github.com/bazelbuild/bazel-gazelle/config"
@@ -89,9 +90,9 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
pyTestFilenames := treeset.NewWith(godsutils.StringComparator)
pyFileNames := treeset.NewWith(godsutils.StringComparator)
- // hasPyBinary controls whether a py_binary target should be generated for
+ // hasPyBinaryEntryPointFile controls whether a single py_binary target should be generated for
// this package or not.
- hasPyBinary := false
+ hasPyBinaryEntryPointFile := false
// hasPyTestEntryPointFile and hasPyTestEntryPointTarget control whether a py_test target should
// be generated for this package or not.
@@ -106,8 +107,8 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
ext := filepath.Ext(f)
if ext == ".py" {
pyFileNames.Add(f)
- if !hasPyBinary && f == pyBinaryEntrypointFilename {
- hasPyBinary = true
+ if !hasPyBinaryEntryPointFile && f == pyBinaryEntrypointFilename {
+ hasPyBinaryEntryPointFile = true
} else if !hasPyTestEntryPointFile && f == pyTestEntrypointFilename {
hasPyTestEntryPointFile = true
} else if f == conftestFilename {
@@ -153,12 +154,17 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
if entry.IsDir() {
// If we are visiting a directory, we determine if we should
// halt digging the tree based on a few criterias:
- // 1. The directory has a BUILD or BUILD.bazel files. Then
+ // 1. We are using per-file generation.
+ // 2. The directory has a BUILD or BUILD.bazel files. Then
// it doesn't matter at all what it has since it's a
// separate Bazel package.
- // 2. (only for fine-grained generation) The directory has
- // an __init__.py, __main__.py or __test__.py, meaning
- // a BUILD file will be generated.
+ // 3. (only for package generation) The directory has an
+ // __init__.py, __main__.py or __test__.py, meaning a
+ // BUILD file will be generated.
+ if cfg.PerFileGeneration() {
+ return fs.SkipDir
+ }
+
if isBazelPackage(path) {
boundaryPackages[path] = struct{}{}
return nil
@@ -213,45 +219,78 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
collisionErrors := singlylinkedlist.New()
- var pyLibrary *rule.Rule
- if !pyLibraryFilenames.Empty() {
- deps, err := parser.parse(pyLibraryFilenames)
+ appendPyLibrary := func(srcs *treeset.Set, pyLibraryTargetName string) {
+ allDeps, mainModules, err := parser.parse(srcs)
if err != nil {
log.Fatalf("ERROR: %v\n", err)
}
- pyLibraryTargetName := cfg.RenderLibraryName(packageName)
-
// Check if a target with the same name we are generating already
// exists, and if it is of a different kind from the one we are
// generating. If so, we have to throw an error since Gazelle won't
// generate it correctly.
- if args.File != nil {
- for _, t := range args.File.Rules {
- if t.Name() == pyLibraryTargetName && t.Kind() != actualPyLibraryKind {
- fqTarget := label.New("", args.Rel, pyLibraryTargetName)
- err := fmt.Errorf("failed to generate target %q of kind %q: "+
- "a target of kind %q with the same name already exists. "+
- "Use the '# gazelle:%s' directive to change the naming convention.",
- fqTarget.String(), actualPyLibraryKind, t.Kind(), pythonconfig.LibraryNamingConvention)
- collisionErrors.Add(err)
+ if err := ensureNoCollision(args.File, pyLibraryTargetName, actualPyLibraryKind); err != nil {
+ fqTarget := label.New("", args.Rel, pyLibraryTargetName)
+ err := fmt.Errorf("failed to generate target %q of kind %q: %w. "+
+ "Use the '# gazelle:%s' directive to change the naming convention.",
+ fqTarget.String(), actualPyLibraryKind, err, pythonconfig.LibraryNamingConvention)
+ collisionErrors.Add(err)
+ }
+
+ if !hasPyBinaryEntryPointFile {
+ // Creating one py_binary target per main module when __main__.py doesn't exist.
+ mainFileNames := make([]string, 0, len(mainModules))
+ for name := range mainModules {
+ mainFileNames = append(mainFileNames, name)
+ }
+ sort.Strings(mainFileNames)
+ for _, filename := range mainFileNames {
+ pyBinaryTargetName := strings.TrimSuffix(filepath.Base(filename), ".py")
+ if err := ensureNoCollision(args.File, pyBinaryTargetName, actualPyBinaryKind); err != nil {
+ fqTarget := label.New("", args.Rel, pyBinaryTargetName)
+ log.Printf("failed to generate target %q of kind %q: %v",
+ fqTarget.String(), actualPyBinaryKind, err)
+ continue
}
+ pyBinary := newTargetBuilder(pyBinaryKind, pyBinaryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
+ addVisibility(visibility).
+ addSrc(filename).
+ addModuleDependencies(mainModules[filename]).
+ generateImportsAttribute().build()
+ result.Gen = append(result.Gen, pyBinary)
+ result.Imports = append(result.Imports, pyBinary.PrivateAttr(config.GazelleImportsKey))
}
}
- pyLibrary = newTargetBuilder(pyLibraryKind, pyLibraryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
+ pyLibrary := newTargetBuilder(pyLibraryKind, pyLibraryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
addVisibility(visibility).
- addSrcs(pyLibraryFilenames).
- addModuleDependencies(deps).
+ addSrcs(srcs).
+ addModuleDependencies(allDeps).
generateImportsAttribute().
build()
result.Gen = append(result.Gen, pyLibrary)
result.Imports = append(result.Imports, pyLibrary.PrivateAttr(config.GazelleImportsKey))
}
+ if cfg.PerFileGeneration() {
+ hasInit, nonEmptyInit := hasLibraryEntrypointFile(args.Dir)
+ pyLibraryFilenames.Each(func(index int, filename interface{}) {
+ pyLibraryTargetName := strings.TrimSuffix(filepath.Base(filename.(string)), ".py")
+ if filename == pyLibraryEntrypointFilename && !nonEmptyInit {
+ return // ignore empty __init__.py.
+ }
+ srcs := treeset.NewWith(godsutils.StringComparator, filename)
+ if cfg.PerFileGenerationIncludeInit() && hasInit && nonEmptyInit {
+ srcs.Add(pyLibraryEntrypointFilename)
+ }
+ appendPyLibrary(srcs, pyLibraryTargetName)
+ })
+ } else if !pyLibraryFilenames.Empty() {
+ appendPyLibrary(pyLibraryFilenames, cfg.RenderLibraryName(packageName))
+ }
- if hasPyBinary {
- deps, err := parser.parseSingle(pyBinaryEntrypointFilename)
+ if hasPyBinaryEntryPointFile {
+ deps, _, err := parser.parseSingle(pyBinaryEntrypointFilename)
if err != nil {
log.Fatalf("ERROR: %v\n", err)
}
@@ -262,17 +301,12 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
// exists, and if it is of a different kind from the one we are
// generating. If so, we have to throw an error since Gazelle won't
// generate it correctly.
- if args.File != nil {
- for _, t := range args.File.Rules {
- if t.Name() == pyBinaryTargetName && t.Kind() != actualPyBinaryKind {
- fqTarget := label.New("", args.Rel, pyBinaryTargetName)
- err := fmt.Errorf("failed to generate target %q of kind %q: "+
- "a target of kind %q with the same name already exists. "+
- "Use the '# gazelle:%s' directive to change the naming convention.",
- fqTarget.String(), actualPyBinaryKind, t.Kind(), pythonconfig.BinaryNamingConvention)
- collisionErrors.Add(err)
- }
- }
+ if err := ensureNoCollision(args.File, pyBinaryTargetName, actualPyBinaryKind); err != nil {
+ fqTarget := label.New("", args.Rel, pyBinaryTargetName)
+ err := fmt.Errorf("failed to generate target %q of kind %q: %w. "+
+ "Use the '# gazelle:%s' directive to change the naming convention.",
+ fqTarget.String(), actualPyBinaryKind, err, pythonconfig.BinaryNamingConvention)
+ collisionErrors.Add(err)
}
pyBinaryTarget := newTargetBuilder(pyBinaryKind, pyBinaryTargetName, pythonProjectRoot, args.Rel, pyFileNames).
@@ -290,7 +324,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
var conftest *rule.Rule
if hasConftestFile {
- deps, err := parser.parseSingle(conftestFilename)
+ deps, _, err := parser.parseSingle(conftestFilename)
if err != nil {
log.Fatalf("ERROR: %v\n", err)
}
@@ -299,16 +333,11 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
// exists, and if it is of a different kind from the one we are
// generating. If so, we have to throw an error since Gazelle won't
// generate it correctly.
- if args.File != nil {
- for _, t := range args.File.Rules {
- if t.Name() == conftestTargetname && t.Kind() != actualPyLibraryKind {
- fqTarget := label.New("", args.Rel, conftestTargetname)
- err := fmt.Errorf("failed to generate target %q of kind %q: "+
- "a target of kind %q with the same name already exists.",
- fqTarget.String(), actualPyLibraryKind, t.Kind())
- collisionErrors.Add(err)
- }
- }
+ if err := ensureNoCollision(args.File, conftestTargetname, actualPyLibraryKind); err != nil {
+ fqTarget := label.New("", args.Rel, conftestTargetname)
+ err := fmt.Errorf("failed to generate target %q of kind %q: %w. ",
+ fqTarget.String(), actualPyLibraryKind, err)
+ collisionErrors.Add(err)
}
conftestTarget := newTargetBuilder(pyLibraryKind, conftestTargetname, pythonProjectRoot, args.Rel, pyFileNames).
@@ -326,7 +355,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
var pyTestTargets []*targetBuilder
newPyTestTargetBuilder := func(srcs *treeset.Set, pyTestTargetName string) *targetBuilder {
- deps, err := parser.parse(srcs)
+ deps, _, err := parser.parse(srcs)
if err != nil {
log.Fatalf("ERROR: %v\n", err)
}
@@ -334,24 +363,20 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
// exists, and if it is of a different kind from the one we are
// generating. If so, we have to throw an error since Gazelle won't
// generate it correctly.
- if args.File != nil {
- for _, t := range args.File.Rules {
- if t.Name() == pyTestTargetName && t.Kind() != actualPyTestKind {
- fqTarget := label.New("", args.Rel, pyTestTargetName)
- err := fmt.Errorf("failed to generate target %q of kind %q: "+
- "a target of kind %q with the same name already exists. "+
- "Use the '# gazelle:%s' directive to change the naming convention.",
- fqTarget.String(), actualPyTestKind, t.Kind(), pythonconfig.TestNamingConvention)
- collisionErrors.Add(err)
- }
- }
+ if err := ensureNoCollision(args.File, pyTestTargetName, actualPyTestKind); err != nil {
+ fqTarget := label.New("", args.Rel, pyTestTargetName)
+ err := fmt.Errorf("failed to generate target %q of kind %q: %w. "+
+ "Use the '# gazelle:%s' directive to change the naming convention.",
+ fqTarget.String(), actualPyTestKind, err, pythonconfig.TestNamingConvention)
+ collisionErrors.Add(err)
}
return newTargetBuilder(pyTestKind, pyTestTargetName, pythonProjectRoot, args.Rel, pyFileNames).
addSrcs(srcs).
addModuleDependencies(deps).
generateImportsAttribute()
}
- if hasPyTestEntryPointFile || hasPyTestEntryPointTarget {
+ if (hasPyTestEntryPointFile || hasPyTestEntryPointTarget || cfg.CoarseGrainedGeneration()) && !cfg.PerFileGeneration() {
+ // Create one py_test target per package
if hasPyTestEntryPointFile {
// Only add the pyTestEntrypointFilename to the pyTestFilenames if
// the file exists on disk.
@@ -376,7 +401,20 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
pyTestFilenames.Each(func(index int, testFile interface{}) {
srcs := treeset.NewWith(godsutils.StringComparator, testFile)
pyTestTargetName := strings.TrimSuffix(filepath.Base(testFile.(string)), ".py")
- pyTestTargets = append(pyTestTargets, newPyTestTargetBuilder(srcs, pyTestTargetName))
+ pyTestTarget := newPyTestTargetBuilder(srcs, pyTestTargetName)
+
+ if hasPyTestEntryPointTarget {
+ entrypointTarget := fmt.Sprintf(":%s", pyTestEntrypointTargetname)
+ main := fmt.Sprintf(":%s", pyTestEntrypointFilename)
+ pyTestTarget.
+ addSrc(entrypointTarget).
+ addResolvedDependency(entrypointTarget).
+ setMain(main)
+ } else if hasPyTestEntryPointFile {
+ pyTestTarget.addSrc(pyTestEntrypointFilename)
+ pyTestTarget.setMain(pyTestEntrypointFilename)
+ }
+ pyTestTargets = append(pyTestTargets, pyTestTarget)
})
}
@@ -429,6 +467,19 @@ func hasEntrypointFile(dir string) bool {
return false
}
+// hasLibraryEntrypointFile returns if the given directory has the library
+// entrypoint file, and if it is non-empty.
+func hasLibraryEntrypointFile(dir string) (bool, bool) {
+ stat, err := os.Stat(filepath.Join(dir, pyLibraryEntrypointFilename))
+ if os.IsNotExist(err) {
+ return false, false
+ }
+ if err != nil {
+ log.Fatalf("ERROR: %v\n", err)
+ }
+ return true, stat.Size() != 0
+}
+
// isEntrypointFile returns whether the given path is an entrypoint file. The
// given path can be absolute or relative.
func isEntrypointFile(path string) bool {
@@ -442,3 +493,15 @@ func isEntrypointFile(path string) bool {
return false
}
}
+
+func ensureNoCollision(file *rule.File, targetName, kind string) error {
+ if file == nil {
+ return nil
+ }
+ for _, t := range file.Rules {
+ if t.Name() == targetName && t.Kind() != kind {
+ return fmt.Errorf("a target of kind %q with the same name already exists", t.Kind())
+ }
+ }
+ return nil
+}
diff --git a/gazelle/python/kinds.go b/gazelle/python/kinds.go
index ab1afb7..941b45b 100644
--- a/gazelle/python/kinds.go
+++ b/gazelle/python/kinds.go
@@ -49,7 +49,8 @@ var pyKinds = map[string]rule.KindInfo{
},
},
pyLibraryKind: {
- MatchAny: true,
+ MatchAny: false,
+ MatchAttrs: []string{"srcs"},
NonEmptyAttrs: map[string]bool{
"deps": true,
"srcs": true,
diff --git a/gazelle/python/lifecycle.go b/gazelle/python/lifecycle.go
index 592b322..6d628e9 100644
--- a/gazelle/python/lifecycle.go
+++ b/gazelle/python/lifecycle.go
@@ -16,14 +16,37 @@ package python
import (
"context"
+ _ "embed"
"github.com/bazelbuild/bazel-gazelle/language"
+ "log"
+ "os"
+)
+
+var (
+ //go:embed helper.zip
+ helperZip []byte
+ helperPath string
)
type LifeCycleManager struct {
language.BaseLifecycleManager
+ pyzFilePath string
}
func (l *LifeCycleManager) Before(ctx context.Context) {
+ helperPath = os.Getenv("GAZELLE_PYTHON_HELPER")
+ if helperPath == "" {
+ pyzFile, err := os.CreateTemp("", "python_zip_")
+ if err != nil {
+ log.Fatalf("failed to write parser zip: %v", err)
+ }
+ defer pyzFile.Close()
+ helperPath = pyzFile.Name()
+ l.pyzFilePath = helperPath
+ if _, err := pyzFile.Write(helperZip); err != nil {
+ log.Fatalf("cannot write %q: %v", helperPath, err)
+ }
+ }
startParserProcess(ctx)
startStdModuleProcess(ctx)
}
@@ -34,4 +57,7 @@ func (l *LifeCycleManager) DoneGeneratingRules() {
func (l *LifeCycleManager) AfterResolvingDeps(ctx context.Context) {
shutdownStdModuleProcess()
+ if l.pyzFilePath != "" {
+ os.Remove(l.pyzFilePath)
+ }
}
diff --git a/gazelle/python/parse.py b/gazelle/python/parse.py
index 6c0ef69..daa6d2b 100644
--- a/gazelle/python/parse.py
+++ b/gazelle/python/parse.py
@@ -22,7 +22,7 @@ import json
import os
import sys
from io import BytesIO
-from tokenize import COMMENT, tokenize
+from tokenize import COMMENT, NAME, OP, STRING, tokenize
def parse_import_statements(content, filepath):
@@ -59,6 +59,30 @@ def parse_comments(content):
return comments
+def parse_main(content):
+ g = tokenize(BytesIO(content.encode("utf-8")).readline)
+ for token_type, token_val, start, _, _ in g:
+ if token_type != NAME or token_val != "if" or start[1] != 0:
+ continue
+ try:
+ token_type, token_val, start, _, _ = next(g)
+ if token_type != NAME or token_val != "__name__":
+ continue
+ token_type, token_val, start, _, _ = next(g)
+ if token_type != OP or token_val != "==":
+ continue
+ token_type, token_val, start, _, _ = next(g)
+ if token_type != STRING or token_val.strip("\"'") != '__main__':
+ continue
+ token_type, token_val, start, _, _ = next(g)
+ if token_type != OP or token_val != ":":
+ continue
+ return True
+ except StopIteration:
+ break
+ return False
+
+
def parse(repo_root, rel_package_path, filename):
rel_filepath = os.path.join(rel_package_path, filename)
abs_filepath = os.path.join(repo_root, rel_filepath)
@@ -70,11 +94,16 @@ def parse(repo_root, rel_package_path, filename):
parse_import_statements, content, rel_filepath
)
comments_future = executor.submit(parse_comments, content)
+ main_future = executor.submit(parse_main, content)
modules = modules_future.result()
comments = comments_future.result()
+ has_main = main_future.result()
+
output = {
+ "filename": filename,
"modules": modules,
"comments": comments,
+ "has_main": has_main,
}
return output
diff --git a/gazelle/python/parse_test.py b/gazelle/python/parse_test.py
new file mode 100644
index 0000000..3ebded4
--- /dev/null
+++ b/gazelle/python/parse_test.py
@@ -0,0 +1,39 @@
+import unittest
+import parse
+
+class TestParse(unittest.TestCase):
+ def test_not_has_main(self):
+ content = "a = 1\nb = 2"
+ self.assertFalse(parse.parse_main(content))
+
+ def test_has_main_in_function(self):
+ content = """
+def foo():
+ if __name__ == "__main__":
+ a = 3
+"""
+ self.assertFalse(parse.parse_main(content))
+
+ def test_has_main(self):
+ content = """
+import unittest
+
+from lib import main
+
+
+class ExampleTest(unittest.TestCase):
+ def test_main(self):
+ self.assertEqual(
+ "",
+ main([["A", 1], ["B", 2]]),
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
+"""
+ self.assertTrue(parse.parse_main(content))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gazelle/python/parser.go b/gazelle/python/parser.go
index 7f10a75..9b00b83 100644
--- a/gazelle/python/parser.go
+++ b/gazelle/python/parser.go
@@ -17,6 +17,7 @@ package python
import (
"bufio"
"context"
+ _ "embed"
"encoding/json"
"fmt"
"io"
@@ -26,59 +27,51 @@ import (
"strings"
"sync"
- "github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/emirpasic/gods/sets/treeset"
godsutils "github.com/emirpasic/gods/utils"
)
var (
+ parserCmd *exec.Cmd
parserStdin io.WriteCloser
parserStdout io.Reader
parserMutex sync.Mutex
)
func startParserProcess(ctx context.Context) {
- parseScriptRunfile, err := bazel.Runfile("python/parse")
- if err != nil {
- log.Printf("failed to initialize parser: %v\n", err)
- os.Exit(1)
- }
-
- cmd := exec.CommandContext(ctx, parseScriptRunfile)
-
- cmd.Stderr = os.Stderr
+ // due to #691, we need a system interpreter to boostrap, part of which is
+ // to locate the hermetic interpreter.
+ parserCmd = exec.CommandContext(ctx, "python3", helperPath, "parse")
+ parserCmd.Stderr = os.Stderr
- stdin, err := cmd.StdinPipe()
+ stdin, err := parserCmd.StdinPipe()
if err != nil {
log.Printf("failed to initialize parser: %v\n", err)
os.Exit(1)
}
parserStdin = stdin
- stdout, err := cmd.StdoutPipe()
+ stdout, err := parserCmd.StdoutPipe()
if err != nil {
log.Printf("failed to initialize parser: %v\n", err)
os.Exit(1)
}
parserStdout = stdout
- if err := cmd.Start(); err != nil {
+ if err := parserCmd.Start(); err != nil {
log.Printf("failed to initialize parser: %v\n", err)
os.Exit(1)
}
-
- go func() {
- if err := cmd.Wait(); err != nil {
- log.Printf("failed to wait for parser: %v\n", err)
- os.Exit(1)
- }
- }()
}
func shutdownParserProcess() {
if err := parserStdin.Close(); err != nil {
fmt.Fprintf(os.Stderr, "error closing parser: %v", err)
}
+
+ if err := parserCmd.Wait(); err != nil {
+ log.Printf("failed to wait for parser: %v\n", err)
+ }
}
// python3Parser implements a parser for Python files that extracts the modules
@@ -108,7 +101,7 @@ func newPython3Parser(
// parseSingle parses a single Python file and returns the extracted modules
// from the import statements as well as the parsed comments.
-func (p *python3Parser) parseSingle(pyFilename string) (*treeset.Set, error) {
+func (p *python3Parser) parseSingle(pyFilename string) (*treeset.Set, map[string]*treeset.Set, error) {
pyFilenames := treeset.NewWith(godsutils.StringComparator)
pyFilenames.Add(pyFilename)
return p.parse(pyFilenames)
@@ -116,7 +109,7 @@ func (p *python3Parser) parseSingle(pyFilename string) (*treeset.Set, error) {
// parse parses multiple Python files and returns the extracted modules from
// the import statements as well as the parsed comments.
-func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, error) {
+func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, map[string]*treeset.Set, error) {
parserMutex.Lock()
defer parserMutex.Unlock()
@@ -129,24 +122,28 @@ func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, error) {
}
encoder := json.NewEncoder(parserStdin)
if err := encoder.Encode(&req); err != nil {
- return nil, fmt.Errorf("failed to parse: %w", err)
+ return nil, nil, fmt.Errorf("failed to parse: %w", err)
}
reader := bufio.NewReader(parserStdout)
data, err := reader.ReadBytes(0)
if err != nil {
- return nil, fmt.Errorf("failed to parse: %w", err)
+ return nil, nil, fmt.Errorf("failed to parse: %w", err)
}
data = data[:len(data)-1]
var allRes []parserResponse
if err := json.Unmarshal(data, &allRes); err != nil {
- return nil, fmt.Errorf("failed to parse: %w", err)
+ return nil, nil, fmt.Errorf("failed to parse: %w", err)
}
+ mainModules := make(map[string]*treeset.Set, len(allRes))
for _, res := range allRes {
+ if res.HasMain {
+ mainModules[res.FileName] = treeset.NewWith(moduleComparator)
+ }
annotations, err := annotationsFromComments(res.Comments)
if err != nil {
- return nil, fmt.Errorf("failed to parse annotations: %w", err)
+ return nil, nil, fmt.Errorf("failed to parse annotations: %w", err)
}
for _, m := range res.Modules {
@@ -163,20 +160,28 @@ func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, error) {
}
modules.Add(m)
+ if res.HasMain {
+ mainModules[res.FileName].Add(m)
+ }
}
}
- return modules, nil
+ return modules, mainModules, nil
}
// parserResponse represents a response returned by the parser.py for a given
// parsed Python module.
type parserResponse struct {
+ // FileName of the parsed module
+ FileName string
// The modules depended by the parsed module.
Modules []module `json:"modules"`
// The comments contained in the parsed module. This contains the
// annotations as they are comments in the Python module.
Comments []comment `json:"comments"`
+ // HasMain indicates whether the Python module has `if __name == "__main__"`
+ // at the top level
+ HasMain bool `json:"has_main"`
}
// module represents a fully-qualified, dot-separated, Python module as seen on
diff --git a/gazelle/python/python_test.go b/gazelle/python/python_test.go
index 79450ad..617b3f8 100644
--- a/gazelle/python/python_test.go
+++ b/gazelle/python/python_test.go
@@ -31,6 +31,7 @@ import (
"time"
"github.com/bazelbuild/bazel-gazelle/testtools"
+ "github.com/bazelbuild/rules_go/go/runfiles"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/ghodss/yaml"
)
@@ -159,6 +160,11 @@ func testPath(t *testing.T, name string, files []bazel.RunfileEntry) {
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Dir = workspaceRoot
+ helperScript, err := runfiles.Rlocation("rules_python_gazelle_plugin/python/helper")
+ if err != nil {
+ t.Fatalf("failed to initialize Python helper: %v", err)
+ }
+ cmd.Env = append(os.Environ(), "GAZELLE_PYTHON_HELPER="+helperScript)
if err := cmd.Run(); err != nil {
var e *exec.ExitError
if !errors.As(err, &e) {
diff --git a/gazelle/python/resolve.go b/gazelle/python/resolve.go
index 46014e5..f019a64 100644
--- a/gazelle/python/resolve.go
+++ b/gazelle/python/resolve.go
@@ -61,11 +61,17 @@ func (py *Resolver) Imports(c *config.Config, r *rule.Rule, f *rule.File) []reso
provides := make([]resolve.ImportSpec, 0, len(srcs)+1)
for _, src := range srcs {
ext := filepath.Ext(src)
- if ext == ".py" {
- pythonProjectRoot := cfg.PythonProjectRoot()
- provide := importSpecFromSrc(pythonProjectRoot, f.Pkg, src)
- provides = append(provides, provide)
+ if ext != ".py" {
+ continue
}
+ if cfg.PerFileGeneration() && len(srcs) > 1 && src == pyLibraryEntrypointFilename {
+ // Do not provide import spec from __init__.py when it is being included as
+ // part of another module.
+ continue
+ }
+ pythonProjectRoot := cfg.PythonProjectRoot()
+ provide := importSpecFromSrc(pythonProjectRoot, f.Pkg, src)
+ provides = append(provides, provide)
}
if len(provides) == 0 {
return nil
@@ -151,10 +157,10 @@ func (py *Resolver) Resolve(
for len(moduleParts) > 1 {
// Iterate back through the possible imports until
// a match is found.
- // For example, "from foo.bar import baz" where bar is a variable, we should try
- // `foo.bar.baz` first, then `foo.bar`, then `foo`. In the first case, the import could be file `baz.py`
- // in the directory `foo/bar`.
- // Or, the import could be variable `bar` in file `foo/bar.py`.
+ // For example, "from foo.bar import baz" where baz is a module, we should try `foo.bar.baz` first, then
+ // `foo.bar`, then `foo`.
+ // In the first case, the import could be file `baz.py` in the directory `foo/bar`.
+ // Or, the import could be variable `baz` in file `foo/bar.py`.
// The import could also be from a standard module, e.g. `six.moves`, where
// the dependency is actually `six`.
moduleParts = moduleParts[:len(moduleParts)-1]
@@ -172,7 +178,7 @@ func (py *Resolver) Resolve(
if override.Repo == from.Repo {
override.Repo = ""
}
- dep := override.String()
+ dep := override.Rel(from.Repo, from.Pkg).String()
deps.Add(dep)
if explainDependency == dep {
log.Printf("Explaining dependency (%s): "+
diff --git a/gazelle/python/std_modules.go b/gazelle/python/std_modules.go
index c537184..8a016af 100644
--- a/gazelle/python/std_modules.go
+++ b/gazelle/python/std_modules.go
@@ -17,6 +17,7 @@ package python
import (
"bufio"
"context"
+ _ "embed"
"fmt"
"io"
"log"
@@ -25,11 +26,10 @@ import (
"strconv"
"strings"
"sync"
-
- "github.com/bazelbuild/rules_go/go/tools/bazel"
)
var (
+ stdModulesCmd *exec.Cmd
stdModulesStdin io.WriteCloser
stdModulesStdout io.Reader
stdModulesMutex sync.Mutex
@@ -39,48 +39,41 @@ var (
func startStdModuleProcess(ctx context.Context) {
stdModulesSeen = make(map[string]struct{})
- stdModulesScriptRunfile, err := bazel.Runfile("python/std_modules")
- if err != nil {
- log.Printf("failed to initialize std_modules: %v\n", err)
- os.Exit(1)
- }
-
- cmd := exec.CommandContext(ctx, stdModulesScriptRunfile)
-
- cmd.Stderr = os.Stderr
+ // due to #691, we need a system interpreter to boostrap, part of which is
+ // to locate the hermetic interpreter.
+ stdModulesCmd = exec.CommandContext(ctx, "python3", helperPath, "std_modules")
+ stdModulesCmd.Stderr = os.Stderr
// All userland site-packages should be ignored.
- cmd.Env = []string{"PYTHONNOUSERSITE=1"}
- stdin, err := cmd.StdinPipe()
+ stdModulesCmd.Env = []string{"PYTHONNOUSERSITE=1"}
+
+ stdin, err := stdModulesCmd.StdinPipe()
if err != nil {
log.Printf("failed to initialize std_modules: %v\n", err)
os.Exit(1)
}
stdModulesStdin = stdin
- stdout, err := cmd.StdoutPipe()
+ stdout, err := stdModulesCmd.StdoutPipe()
if err != nil {
log.Printf("failed to initialize std_modules: %v\n", err)
os.Exit(1)
}
stdModulesStdout = stdout
- if err := cmd.Start(); err != nil {
+ if err := stdModulesCmd.Start(); err != nil {
log.Printf("failed to initialize std_modules: %v\n", err)
os.Exit(1)
}
-
- go func() {
- if err := cmd.Wait(); err != nil {
- log.Printf("failed to wait for std_modules: %v\n", err)
- os.Exit(1)
- }
- }()
}
func shutdownStdModuleProcess() {
if err := stdModulesStdin.Close(); err != nil {
fmt.Fprintf(os.Stderr, "error closing std module: %v", err)
}
+
+ if err := stdModulesCmd.Wait(); err != nil {
+ log.Printf("failed to wait for std_modules: %v\n", err)
+ }
}
func isStdModule(m module) (bool, error) {
diff --git a/gazelle/python/target.go b/gazelle/python/target.go
index fdc99fc..e310405 100644
--- a/gazelle/python/target.go
+++ b/gazelle/python/target.go
@@ -122,6 +122,11 @@ func (t *targetBuilder) setTestonly() *targetBuilder {
// case, the value we add is on Bazel sub-packages to be able to perform imports
// relative to the root project package.
func (t *targetBuilder) generateImportsAttribute() *targetBuilder {
+ if t.pythonProjectRoot == "" {
+ // When gazelle:python_root is not set or is at the root of the repo, we don't need
+ // to set imports, because that's the Bazel's default.
+ return t
+ }
p, _ := filepath.Rel(t.bzlPackage, t.pythonProjectRoot)
p = filepath.Clean(p)
if p == "." {
diff --git a/gazelle/python/testdata/binary_without_entrypoint/BUILD.in b/gazelle/python/testdata/binary_without_entrypoint/BUILD.in
new file mode 100644
index 0000000..1177dce
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/BUILD.in
@@ -0,0 +1,8 @@
+# gazelle:python_library_naming_convention py_default_library
+# gazelle:resolve py numpy @pip//:numpy
+# gazelle:resolve py pandas @pip//:pandas
+
+filegroup(
+ name = "collided_main",
+ srcs = ["collided_main.py"],
+)
diff --git a/gazelle/python/testdata/binary_without_entrypoint/BUILD.out b/gazelle/python/testdata/binary_without_entrypoint/BUILD.out
new file mode 100644
index 0000000..9af8152
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/BUILD.out
@@ -0,0 +1,47 @@
+load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
+
+# gazelle:python_library_naming_convention py_default_library
+# gazelle:resolve py numpy @pip//:numpy
+# gazelle:resolve py pandas @pip//:pandas
+
+filegroup(
+ name = "collided_main",
+ srcs = ["collided_main.py"],
+)
+
+py_binary(
+ name = "main",
+ srcs = ["main.py"],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ ":py_default_library",
+ "@pip//:pandas",
+ ],
+)
+
+py_binary(
+ name = "main2",
+ srcs = ["main2.py"],
+ visibility = ["//:__subpackages__"],
+ deps = [":py_default_library"],
+)
+
+py_library(
+ name = "py_default_library",
+ srcs = [
+ "__init__.py",
+ "collided_main.py",
+ "main.py",
+ "main2.py",
+ ],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ "@pip//:numpy",
+ "@pip//:pandas",
+ ],
+)
+
+py_test(
+ name = "main_test",
+ srcs = ["main_test.py"],
+) \ No newline at end of file
diff --git a/gazelle/python/testdata/binary_without_entrypoint/README.md b/gazelle/python/testdata/binary_without_entrypoint/README.md
new file mode 100644
index 0000000..e91250d
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/README.md
@@ -0,0 +1,4 @@
+# Binary without entrypoint
+
+This test case asserts that when there is no __main__.py, a py_binary is generated per main module, unless a main
+module main collides with existing target name.
diff --git a/gazelle/python/testdata/binary_without_entrypoint/WORKSPACE b/gazelle/python/testdata/binary_without_entrypoint/WORKSPACE
new file mode 100644
index 0000000..faff6af
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/WORKSPACE
@@ -0,0 +1 @@
+# This is a Bazel workspace for the Gazelle test data.
diff --git a/gazelle/python/testdata/binary_without_entrypoint/__init__.py b/gazelle/python/testdata/binary_without_entrypoint/__init__.py
new file mode 100644
index 0000000..7307559
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/__init__.py
@@ -0,0 +1,15 @@
+# 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.
+
+# For test purposes only.
diff --git a/gazelle/python/testdata/binary_without_entrypoint/collided_main.py b/gazelle/python/testdata/binary_without_entrypoint/collided_main.py
new file mode 100644
index 0000000..3bf59c7
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/collided_main.py
@@ -0,0 +1,4 @@
+import numpy
+
+if __name__ == "__main__":
+ run() \ No newline at end of file
diff --git a/gazelle/python/testdata/binary_without_entrypoint/main.py b/gazelle/python/testdata/binary_without_entrypoint/main.py
new file mode 100644
index 0000000..f7b3170
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/main.py
@@ -0,0 +1,5 @@
+import collided_main
+import pandas
+
+if __name__ == "__main__":
+ run() \ No newline at end of file
diff --git a/gazelle/python/testdata/binary_without_entrypoint/main2.py b/gazelle/python/testdata/binary_without_entrypoint/main2.py
new file mode 100644
index 0000000..a82a5e6
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/main2.py
@@ -0,0 +1,4 @@
+import collided_main
+
+if __name__ == "__main__":
+ run()
diff --git a/gazelle/python/testdata/binary_without_entrypoint/main_test.py b/gazelle/python/testdata/binary_without_entrypoint/main_test.py
new file mode 100644
index 0000000..505a766
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/main_test.py
@@ -0,0 +1,7 @@
+import unittest
+
+class TestMain(unittest.unittest):
+ pass
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gazelle/python/testdata/binary_without_entrypoint/test.yaml b/gazelle/python/testdata/binary_without_entrypoint/test.yaml
new file mode 100644
index 0000000..44e4ae8
--- /dev/null
+++ b/gazelle/python/testdata/binary_without_entrypoint/test.yaml
@@ -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.
+
+---
+expect:
+ stderr: |
+ gazelle: failed to generate target "//:collided_main" of kind "py_binary": a target of kind "filegroup" with the same name already exists
diff --git a/gazelle/python/testdata/dependency_resolution_order/BUILD.out b/gazelle/python/testdata/dependency_resolution_order/BUILD.out
index 3ea83eb..eebe6c3 100644
--- a/gazelle/python/testdata/dependency_resolution_order/BUILD.out
+++ b/gazelle/python/testdata/dependency_resolution_order/BUILD.out
@@ -9,6 +9,6 @@ py_library(
deps = [
"//baz",
"//somewhere/bar",
- "@gazelle_python_test_some_foo//:pkg",
+ "@gazelle_python_test//some_foo",
],
)
diff --git a/gazelle/python/testdata/dependency_resolution_order/bar/BUILD.out b/gazelle/python/testdata/dependency_resolution_order/bar/BUILD.out
index da9915d..5291471 100644
--- a/gazelle/python/testdata/dependency_resolution_order/bar/BUILD.out
+++ b/gazelle/python/testdata/dependency_resolution_order/bar/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "bar",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/dependency_resolution_order/baz/BUILD.out b/gazelle/python/testdata/dependency_resolution_order/baz/BUILD.out
index 749fd3d..fadf5c1 100644
--- a/gazelle/python/testdata/dependency_resolution_order/baz/BUILD.out
+++ b/gazelle/python/testdata/dependency_resolution_order/baz/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "baz",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/dependency_resolution_order/foo/BUILD.out b/gazelle/python/testdata/dependency_resolution_order/foo/BUILD.out
index 4404d30..58498ee 100644
--- a/gazelle/python/testdata/dependency_resolution_order/foo/BUILD.out
+++ b/gazelle/python/testdata/dependency_resolution_order/foo/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "foo",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/dependency_resolution_order/somewhere/bar/BUILD.out b/gazelle/python/testdata/dependency_resolution_order/somewhere/bar/BUILD.out
index a0d421b..5291471 100644
--- a/gazelle/python/testdata/dependency_resolution_order/somewhere/bar/BUILD.out
+++ b/gazelle/python/testdata/dependency_resolution_order/somewhere/bar/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "bar",
srcs = ["__init__.py"],
- imports = ["../.."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/dont_rename_target/BUILD.in b/gazelle/python/testdata/dont_rename_target/BUILD.in
index 33e8ec2..e9bc0e6 100644
--- a/gazelle/python/testdata/dont_rename_target/BUILD.in
+++ b/gazelle/python/testdata/dont_rename_target/BUILD.in
@@ -2,4 +2,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "my_custom_target",
+ srcs = ["__init__.py"],
)
diff --git a/gazelle/python/testdata/file_name_matches_import_statement/BUILD.out b/gazelle/python/testdata/file_name_matches_import_statement/BUILD.out
index 0216e4b..ae1ba81 100644
--- a/gazelle/python/testdata/file_name_matches_import_statement/BUILD.out
+++ b/gazelle/python/testdata/file_name_matches_import_statement/BUILD.out
@@ -7,5 +7,5 @@ py_library(
"rest_framework.py",
],
visibility = ["//:__subpackages__"],
- deps = ["@gazelle_python_test_djangorestframework//:pkg"],
+ deps = ["@gazelle_python_test//djangorestframework"],
)
diff --git a/gazelle/python/testdata/first_party_file_and_directory_modules/foo/BUILD.out b/gazelle/python/testdata/first_party_file_and_directory_modules/foo/BUILD.out
index 3decd90..8c54e3c 100644
--- a/gazelle/python/testdata/first_party_file_and_directory_modules/foo/BUILD.out
+++ b/gazelle/python/testdata/first_party_file_and_directory_modules/foo/BUILD.out
@@ -6,7 +6,6 @@ py_library(
"__init__.py",
"bar.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = ["//one"],
)
diff --git a/gazelle/python/testdata/first_party_file_and_directory_modules/one/BUILD.out b/gazelle/python/testdata/first_party_file_and_directory_modules/one/BUILD.out
index 7063141..3ae64b6 100644
--- a/gazelle/python/testdata/first_party_file_and_directory_modules/one/BUILD.out
+++ b/gazelle/python/testdata/first_party_file_and_directory_modules/one/BUILD.out
@@ -6,6 +6,5 @@ py_library(
"__init__.py",
"two.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/from_imports/foo/BUILD.out b/gazelle/python/testdata/from_imports/foo/BUILD.out
index 4404d30..58498ee 100644
--- a/gazelle/python/testdata/from_imports/foo/BUILD.out
+++ b/gazelle/python/testdata/from_imports/foo/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "foo",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/from_imports/import_from_init_py/BUILD.out b/gazelle/python/testdata/from_imports/import_from_init_py/BUILD.out
index 99b4861..8098aa7 100644
--- a/gazelle/python/testdata/from_imports/import_from_init_py/BUILD.out
+++ b/gazelle/python/testdata/from_imports/import_from_init_py/BUILD.out
@@ -3,7 +3,6 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "import_from_init_py",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = ["//foo/bar"],
) \ No newline at end of file
diff --git a/gazelle/python/testdata/from_imports/import_from_multiple/BUILD.out b/gazelle/python/testdata/from_imports/import_from_multiple/BUILD.out
index d8219bb..f5e113b 100644
--- a/gazelle/python/testdata/from_imports/import_from_multiple/BUILD.out
+++ b/gazelle/python/testdata/from_imports/import_from_multiple/BUILD.out
@@ -3,7 +3,6 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "import_from_multiple",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = [
"//foo/bar",
diff --git a/gazelle/python/testdata/from_imports/import_nested_file/BUILD.out b/gazelle/python/testdata/from_imports/import_nested_file/BUILD.out
index 662da9c..930216b 100644
--- a/gazelle/python/testdata/from_imports/import_nested_file/BUILD.out
+++ b/gazelle/python/testdata/from_imports/import_nested_file/BUILD.out
@@ -3,7 +3,6 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "import_nested_file",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = ["//foo/bar:baz"],
) \ No newline at end of file
diff --git a/gazelle/python/testdata/from_imports/import_nested_module/BUILD.out b/gazelle/python/testdata/from_imports/import_nested_module/BUILD.out
index ec6da50..51d3b8c 100644
--- a/gazelle/python/testdata/from_imports/import_nested_module/BUILD.out
+++ b/gazelle/python/testdata/from_imports/import_nested_module/BUILD.out
@@ -3,7 +3,6 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "import_nested_module",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = ["//foo/bar"],
) \ No newline at end of file
diff --git a/gazelle/python/testdata/from_imports/import_nested_var/BUILD.out b/gazelle/python/testdata/from_imports/import_nested_var/BUILD.out
index 8ee527e..2129c32 100644
--- a/gazelle/python/testdata/from_imports/import_nested_var/BUILD.out
+++ b/gazelle/python/testdata/from_imports/import_nested_var/BUILD.out
@@ -3,7 +3,6 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "import_nested_var",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = ["//foo/bar:baz"],
) \ No newline at end of file
diff --git a/gazelle/python/testdata/from_imports/import_top_level_var/BUILD.out b/gazelle/python/testdata/from_imports/import_top_level_var/BUILD.out
index 6b584d7..c8ef6f4 100644
--- a/gazelle/python/testdata/from_imports/import_top_level_var/BUILD.out
+++ b/gazelle/python/testdata/from_imports/import_top_level_var/BUILD.out
@@ -3,7 +3,6 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "import_top_level_var",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
deps = ["//foo"],
) \ No newline at end of file
diff --git a/gazelle/python/testdata/from_imports/std_module/BUILD.out b/gazelle/python/testdata/from_imports/std_module/BUILD.out
index 4903999..b3597a9 100644
--- a/gazelle/python/testdata/from_imports/std_module/BUILD.out
+++ b/gazelle/python/testdata/from_imports/std_module/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "std_module",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
) \ No newline at end of file
diff --git a/gazelle/python/testdata/ignored_invalid_imported_module/BUILD.out b/gazelle/python/testdata/ignored_invalid_imported_module/BUILD.out
index b8c936a..4744166 100644
--- a/gazelle/python/testdata/ignored_invalid_imported_module/BUILD.out
+++ b/gazelle/python/testdata/ignored_invalid_imported_module/BUILD.out
@@ -4,5 +4,5 @@ py_library(
name = "ignored_invalid_imported_module",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
- deps = ["@gazelle_python_test_foo//:pkg"],
+ deps = ["@gazelle_python_test//foo"],
)
diff --git a/gazelle/python/testdata/monorepo/coarse_grained/BUILD.out b/gazelle/python/testdata/monorepo/coarse_grained/BUILD.out
index b11cbbd..3a33111 100644
--- a/gazelle/python/testdata/monorepo/coarse_grained/BUILD.out
+++ b/gazelle/python/testdata/monorepo/coarse_grained/BUILD.out
@@ -1,4 +1,4 @@
-load("@rules_python//python:defs.bzl", "py_library")
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
# gazelle:python_extension enabled
# gazelle:python_root
@@ -16,5 +16,14 @@ py_library(
"foo/__init__.py",
],
visibility = ["//:__subpackages__"],
- deps = ["@root_pip_deps_rootboto3//:pkg"],
+ deps = ["@root_pip_deps//rootboto3"],
+)
+
+py_test(
+ name = "coarse_grained_test",
+ srcs = [
+ "bar/bar_test.py",
+ "foo/bar/bar_test.py",
+ ],
+ main = "__test__.py",
)
diff --git a/gazelle/python/testdata/monorepo/coarse_grained/bar/bar_test.py b/gazelle/python/testdata/monorepo/coarse_grained/bar/bar_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/monorepo/coarse_grained/bar/bar_test.py
diff --git a/gazelle/python/testdata/monorepo/coarse_grained/foo/bar/bar_test.py b/gazelle/python/testdata/monorepo/coarse_grained/foo/bar/bar_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/monorepo/coarse_grained/foo/bar/bar_test.py
diff --git a/gazelle/python/testdata/monorepo/one/BUILD.out b/gazelle/python/testdata/monorepo/one/BUILD.out
index 5098cc9..af11746 100644
--- a/gazelle/python/testdata/monorepo/one/BUILD.out
+++ b/gazelle/python/testdata/monorepo/one/BUILD.out
@@ -12,6 +12,6 @@ py_binary(
"//one/bar",
"//one/bar/baz:modified_name_baz",
"//one/foo",
- "@one_pip_deps_oneboto3//:pkg",
+ "@one_pip_deps//oneboto3",
],
)
diff --git a/gazelle/python/testdata/monorepo/one/bar/BUILD.out b/gazelle/python/testdata/monorepo/one/bar/BUILD.out
index 6ee6515..7a4a1d6 100644
--- a/gazelle/python/testdata/monorepo/one/bar/BUILD.out
+++ b/gazelle/python/testdata/monorepo/one/bar/BUILD.out
@@ -8,5 +8,5 @@ py_library(
"//one:__subpackages__",
"//three:__subpackages__",
],
- deps = ["@one_pip_deps_oneboto3//:pkg"],
+ deps = ["@one_pip_deps//oneboto3"],
)
diff --git a/gazelle/python/testdata/monorepo/three/BUILD.out b/gazelle/python/testdata/monorepo/three/BUILD.out
index 78a3927..2620d70 100644
--- a/gazelle/python/testdata/monorepo/three/BUILD.out
+++ b/gazelle/python/testdata/monorepo/three/BUILD.out
@@ -15,7 +15,7 @@ py_library(
"//one/bar",
"//one/bar/baz:modified_name_baz",
"//one/foo",
- "@root_pip_deps_rootboto4//:pkg",
- "@three_pip_deps_threeboto3//:pkg",
+ "@root_pip_deps//rootboto4",
+ "@three_pip_deps//threeboto3",
],
)
diff --git a/gazelle/python/testdata/monorepo/two/BUILD.out b/gazelle/python/testdata/monorepo/two/BUILD.out
index 9cda007..cf22945 100644
--- a/gazelle/python/testdata/monorepo/two/BUILD.out
+++ b/gazelle/python/testdata/monorepo/two/BUILD.out
@@ -10,6 +10,6 @@ py_library(
visibility = ["//two:__subpackages__"],
deps = [
"//one/foo",
- "@two_pip_deps_twoboto3//:pkg",
+ "@two_pip_deps//twoboto3",
],
)
diff --git a/gazelle/python/testdata/naming_convention/dont_rename/BUILD.out b/gazelle/python/testdata/naming_convention/dont_rename/BUILD.out
index 4d4ead8..8d418be 100644
--- a/gazelle/python/testdata/naming_convention/dont_rename/BUILD.out
+++ b/gazelle/python/testdata/naming_convention/dont_rename/BUILD.out
@@ -3,14 +3,12 @@ load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
py_library(
name = "dont_rename",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
py_binary(
name = "my_dont_rename_binary",
srcs = ["__main__.py"],
- imports = [".."],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [":dont_rename"],
@@ -19,7 +17,6 @@ py_binary(
py_test(
name = "my_dont_rename_test",
srcs = ["__test__.py"],
- imports = [".."],
main = "__test__.py",
deps = [":dont_rename"],
)
diff --git a/gazelle/python/testdata/naming_convention/resolve_conflict/BUILD.out b/gazelle/python/testdata/naming_convention/resolve_conflict/BUILD.out
index 3fa5de2..e155fa6 100644
--- a/gazelle/python/testdata/naming_convention/resolve_conflict/BUILD.out
+++ b/gazelle/python/testdata/naming_convention/resolve_conflict/BUILD.out
@@ -9,14 +9,12 @@ go_test(name = "resolve_conflict_test")
py_library(
name = "my_resolve_conflict_library",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
py_binary(
name = "my_resolve_conflict_binary",
srcs = ["__main__.py"],
- imports = [".."],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [":my_resolve_conflict_library"],
@@ -25,7 +23,6 @@ py_binary(
py_test(
name = "my_resolve_conflict_test",
srcs = ["__test__.py"],
- imports = [".."],
main = "__test__.py",
deps = [":my_resolve_conflict_library"],
)
diff --git a/gazelle/python/testdata/per_file/BUILD.in b/gazelle/python/testdata/per_file/BUILD.in
new file mode 100644
index 0000000..01b0904
--- /dev/null
+++ b/gazelle/python/testdata/per_file/BUILD.in
@@ -0,0 +1,11 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+# gazelle:python_generation_mode file
+
+# This target should be kept unmodified by Gazelle.
+py_library(
+ name = "custom",
+ srcs = ["bar.py"],
+ visibility = ["//visibility:private"],
+ tags = ["cant_touch_this"],
+)
diff --git a/gazelle/python/testdata/per_file/BUILD.out b/gazelle/python/testdata/per_file/BUILD.out
new file mode 100644
index 0000000..6deada8
--- /dev/null
+++ b/gazelle/python/testdata/per_file/BUILD.out
@@ -0,0 +1,34 @@
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
+
+# gazelle:python_generation_mode file
+
+# This target should be kept unmodified by Gazelle.
+py_library(
+ name = "custom",
+ srcs = ["bar.py"],
+ tags = ["cant_touch_this"],
+ visibility = ["//visibility:private"],
+)
+
+py_library(
+ name = "baz",
+ srcs = ["baz.py"],
+ visibility = ["//:__subpackages__"],
+)
+
+py_library(
+ name = "foo",
+ srcs = ["foo.py"],
+ visibility = ["//:__subpackages__"],
+ deps = [":custom"],
+)
+
+py_test(
+ name = "bar_test",
+ srcs = ["bar_test.py"],
+)
+
+py_test(
+ name = "foo_test",
+ srcs = ["foo_test.py"],
+)
diff --git a/gazelle/python/testdata/per_file/README.md b/gazelle/python/testdata/per_file/README.md
new file mode 100644
index 0000000..3ddeb21
--- /dev/null
+++ b/gazelle/python/testdata/per_file/README.md
@@ -0,0 +1,5 @@
+# Per-file generation
+
+This test case generates one `py_library` per file.
+
+`__init__.py` is left empty so no target is generated for it.
diff --git a/gazelle/python/testdata/per_file/WORKSPACE b/gazelle/python/testdata/per_file/WORKSPACE
new file mode 100644
index 0000000..faff6af
--- /dev/null
+++ b/gazelle/python/testdata/per_file/WORKSPACE
@@ -0,0 +1 @@
+# This is a Bazel workspace for the Gazelle test data.
diff --git a/gazelle/python/testdata/per_file/__init__.py b/gazelle/python/testdata/per_file/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file/__init__.py
diff --git a/gazelle/python/testdata/per_file/bar.py b/gazelle/python/testdata/per_file/bar.py
new file mode 100644
index 0000000..7307559
--- /dev/null
+++ b/gazelle/python/testdata/per_file/bar.py
@@ -0,0 +1,15 @@
+# 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.
+
+# For test purposes only.
diff --git a/gazelle/python/testdata/per_file/bar_test.py b/gazelle/python/testdata/per_file/bar_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file/bar_test.py
diff --git a/gazelle/python/testdata/per_file/baz.py b/gazelle/python/testdata/per_file/baz.py
new file mode 100644
index 0000000..7307559
--- /dev/null
+++ b/gazelle/python/testdata/per_file/baz.py
@@ -0,0 +1,15 @@
+# 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.
+
+# For test purposes only.
diff --git a/gazelle/python/testdata/per_file/foo.py b/gazelle/python/testdata/per_file/foo.py
new file mode 100644
index 0000000..c000990
--- /dev/null
+++ b/gazelle/python/testdata/per_file/foo.py
@@ -0,0 +1,15 @@
+# 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 bar
diff --git a/gazelle/python/testdata/per_file/foo_test.py b/gazelle/python/testdata/per_file/foo_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file/foo_test.py
diff --git a/gazelle/python/testdata/per_file/test.yaml b/gazelle/python/testdata/per_file/test.yaml
new file mode 100644
index 0000000..fcea777
--- /dev/null
+++ b/gazelle/python/testdata/per_file/test.yaml
@@ -0,0 +1,15 @@
+# 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.
+
+---
diff --git a/gazelle/python/testdata/per_file_non_empty_init/BUILD.in b/gazelle/python/testdata/per_file_non_empty_init/BUILD.in
new file mode 100644
index 0000000..f76a3d0
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/BUILD.in
@@ -0,0 +1,4 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+# gazelle:python_generation_mode file
+# gazelle:python_generation_mode_per_file_include_init true
diff --git a/gazelle/python/testdata/per_file_non_empty_init/BUILD.out b/gazelle/python/testdata/per_file_non_empty_init/BUILD.out
new file mode 100644
index 0000000..ee4a417
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/BUILD.out
@@ -0,0 +1,20 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+# gazelle:python_generation_mode file
+# gazelle:python_generation_mode_per_file_include_init true
+
+py_library(
+ name = "__init__",
+ srcs = ["__init__.py"],
+ visibility = ["//:__subpackages__"],
+ deps = [":foo"],
+)
+
+py_library(
+ name = "foo",
+ srcs = [
+ "__init__.py",
+ "foo.py",
+ ],
+ visibility = ["//:__subpackages__"],
+)
diff --git a/gazelle/python/testdata/per_file_non_empty_init/README.md b/gazelle/python/testdata/per_file_non_empty_init/README.md
new file mode 100644
index 0000000..6e6e9e2
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/README.md
@@ -0,0 +1,3 @@
+# Per-file generation
+
+This test case generates one `py_library` per file, including `__init__.py`.
diff --git a/gazelle/python/testdata/per_file_non_empty_init/WORKSPACE b/gazelle/python/testdata/per_file_non_empty_init/WORKSPACE
new file mode 100644
index 0000000..faff6af
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/WORKSPACE
@@ -0,0 +1 @@
+# This is a Bazel workspace for the Gazelle test data.
diff --git a/gazelle/python/testdata/per_file_non_empty_init/__init__.py b/gazelle/python/testdata/per_file_non_empty_init/__init__.py
new file mode 100644
index 0000000..492cbc0
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/__init__.py
@@ -0,0 +1,15 @@
+# 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 foo
diff --git a/gazelle/python/testdata/per_file_non_empty_init/foo.py b/gazelle/python/testdata/per_file_non_empty_init/foo.py
new file mode 100644
index 0000000..7307559
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/foo.py
@@ -0,0 +1,15 @@
+# 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.
+
+# For test purposes only.
diff --git a/gazelle/python/testdata/per_file_non_empty_init/test.yaml b/gazelle/python/testdata/per_file_non_empty_init/test.yaml
new file mode 100644
index 0000000..fcea777
--- /dev/null
+++ b/gazelle/python/testdata/per_file_non_empty_init/test.yaml
@@ -0,0 +1,15 @@
+# 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.
+
+---
diff --git a/gazelle/python/testdata/per_file_subdirs/BUILD.in b/gazelle/python/testdata/per_file_subdirs/BUILD.in
new file mode 100644
index 0000000..a5853f6
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/BUILD.in
@@ -0,0 +1,3 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+# gazelle:python_generation_mode file
diff --git a/gazelle/python/testdata/per_file_subdirs/BUILD.out b/gazelle/python/testdata/per_file_subdirs/BUILD.out
new file mode 100644
index 0000000..69c42e0
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/BUILD.out
@@ -0,0 +1,10 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+# gazelle:python_generation_mode file
+
+py_library(
+ name = "foo",
+ srcs = ["foo.py"],
+ visibility = ["//:__subpackages__"],
+ deps = ["//bar:__init__"],
+)
diff --git a/gazelle/python/testdata/per_file_subdirs/README.md b/gazelle/python/testdata/per_file_subdirs/README.md
new file mode 100644
index 0000000..9eda2fa
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/README.md
@@ -0,0 +1,3 @@
+# Per-file generation
+
+This test case generates one `py_library` per file in subdirectories.
diff --git a/gazelle/python/testdata/per_file_subdirs/WORKSPACE b/gazelle/python/testdata/per_file_subdirs/WORKSPACE
new file mode 100644
index 0000000..faff6af
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/WORKSPACE
@@ -0,0 +1 @@
+# This is a Bazel workspace for the Gazelle test data.
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/BUILD.in b/gazelle/python/testdata/per_file_subdirs/bar/BUILD.in
new file mode 100644
index 0000000..4fc674a
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/BUILD.in
@@ -0,0 +1 @@
+# gazelle:python_generation_mode_per_file_include_init true
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/BUILD.out b/gazelle/python/testdata/per_file_subdirs/bar/BUILD.out
new file mode 100644
index 0000000..8835fb2
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/BUILD.out
@@ -0,0 +1,45 @@
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
+
+# gazelle:python_generation_mode_per_file_include_init true
+
+py_library(
+ name = "__init__",
+ srcs = ["__init__.py"],
+ visibility = ["//:__subpackages__"],
+)
+
+py_library(
+ name = "bar",
+ srcs = [
+ "__init__.py",
+ "bar.py",
+ ],
+ visibility = ["//:__subpackages__"],
+)
+
+py_library(
+ name = "foo",
+ srcs = [
+ "__init__.py",
+ "foo.py",
+ ],
+ visibility = ["//:__subpackages__"],
+)
+
+py_test(
+ name = "bar_test",
+ srcs = [
+ "__test__.py",
+ "bar_test.py",
+ ],
+ main = "__test__.py",
+)
+
+py_test(
+ name = "foo_test",
+ srcs = [
+ "__test__.py",
+ "foo_test.py",
+ ],
+ main = "__test__.py",
+)
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/__init__.py b/gazelle/python/testdata/per_file_subdirs/bar/__init__.py
new file mode 100644
index 0000000..5799152
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/__init__.py
@@ -0,0 +1,15 @@
+# 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 .foo import func
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/__test__.py b/gazelle/python/testdata/per_file_subdirs/bar/__test__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/__test__.py
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/bar.py b/gazelle/python/testdata/per_file_subdirs/bar/bar.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/bar.py
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/bar_test.py b/gazelle/python/testdata/per_file_subdirs/bar/bar_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/bar_test.py
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/foo.py b/gazelle/python/testdata/per_file_subdirs/bar/foo.py
new file mode 100644
index 0000000..59eb08c
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/foo.py
@@ -0,0 +1,16 @@
+# 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.
+
+def func():
+ pass
diff --git a/gazelle/python/testdata/per_file_subdirs/bar/foo_test.py b/gazelle/python/testdata/per_file_subdirs/bar/foo_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/bar/foo_test.py
diff --git a/gazelle/python/testdata/per_file_subdirs/baz/baz.py b/gazelle/python/testdata/per_file_subdirs/baz/baz.py
new file mode 100644
index 0000000..5256394
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/baz/baz.py
@@ -0,0 +1,15 @@
+# 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 bar.foo import func
diff --git a/gazelle/python/testdata/per_file_subdirs/foo.py b/gazelle/python/testdata/per_file_subdirs/foo.py
new file mode 100644
index 0000000..b5e6cff
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/foo.py
@@ -0,0 +1,15 @@
+# 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 bar import func
diff --git a/gazelle/python/testdata/per_file_subdirs/test.yaml b/gazelle/python/testdata/per_file_subdirs/test.yaml
new file mode 100644
index 0000000..fcea777
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/test.yaml
@@ -0,0 +1,15 @@
+# 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.
+
+---
diff --git a/gazelle/python/testdata/per_file_subdirs/test_target/BUILD.in b/gazelle/python/testdata/per_file_subdirs/test_target/BUILD.in
new file mode 100644
index 0000000..b5733da
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/test_target/BUILD.in
@@ -0,0 +1,3 @@
+some_target(
+ name = "__test__",
+)
diff --git a/gazelle/python/testdata/per_file_subdirs/test_target/BUILD.out b/gazelle/python/testdata/per_file_subdirs/test_target/BUILD.out
new file mode 100644
index 0000000..f4a9236
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/test_target/BUILD.out
@@ -0,0 +1,25 @@
+load("@rules_python//python:defs.bzl", "py_test")
+
+some_target(
+ name = "__test__",
+)
+
+py_test(
+ name = "a_test",
+ srcs = [
+ "a_test.py",
+ ":__test__",
+ ],
+ main = ":__test__.py",
+ deps = [":__test__"],
+)
+
+py_test(
+ name = "b_test",
+ srcs = [
+ "b_test.py",
+ ":__test__",
+ ],
+ main = ":__test__.py",
+ deps = [":__test__"],
+)
diff --git a/gazelle/python/testdata/per_file_subdirs/test_target/a_test.py b/gazelle/python/testdata/per_file_subdirs/test_target/a_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/test_target/a_test.py
diff --git a/gazelle/python/testdata/per_file_subdirs/test_target/b_test.py b/gazelle/python/testdata/per_file_subdirs/test_target/b_test.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/per_file_subdirs/test_target/b_test.py
diff --git a/gazelle/python/testdata/python_ignore_dependencies_directive/BUILD.out b/gazelle/python/testdata/python_ignore_dependencies_directive/BUILD.out
index 3fb91f5..7afe61b 100644
--- a/gazelle/python/testdata/python_ignore_dependencies_directive/BUILD.out
+++ b/gazelle/python/testdata/python_ignore_dependencies_directive/BUILD.out
@@ -7,5 +7,5 @@ py_library(
name = "python_ignore_dependencies_directive",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
- deps = ["@gazelle_python_test_boto3//:pkg"],
+ deps = ["@gazelle_python_test//boto3"],
)
diff --git a/gazelle/python/testdata/python_ignore_files_directive/bar/BUILD.out b/gazelle/python/testdata/python_ignore_files_directive/bar/BUILD.out
index af3c398..94259f9 100644
--- a/gazelle/python/testdata/python_ignore_files_directive/bar/BUILD.out
+++ b/gazelle/python/testdata/python_ignore_files_directive/bar/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "bar",
srcs = ["baz.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/python_target_with_test_in_name/BUILD.out b/gazelle/python/testdata/python_target_with_test_in_name/BUILD.out
index a46f5c4..32e899b 100644
--- a/gazelle/python/testdata/python_target_with_test_in_name/BUILD.out
+++ b/gazelle/python/testdata/python_target_with_test_in_name/BUILD.out
@@ -11,7 +11,7 @@ py_test(
srcs = ["real_test.py"],
deps = [
":python_target_with_test_in_name",
- "@gazelle_python_test_boto3//:pkg",
+ "@gazelle_python_test//boto3",
],
)
diff --git a/gazelle/python/testdata/relative_imports/BUILD.in b/gazelle/python/testdata/relative_imports/BUILD.in
index e69de29..c04b5e5 100644
--- a/gazelle/python/testdata/relative_imports/BUILD.in
+++ b/gazelle/python/testdata/relative_imports/BUILD.in
@@ -0,0 +1 @@
+# gazelle:resolve py resolved_package //package2:resolved_package
diff --git a/gazelle/python/testdata/relative_imports/BUILD.out b/gazelle/python/testdata/relative_imports/BUILD.out
index 2c08627..bf95244 100644
--- a/gazelle/python/testdata/relative_imports/BUILD.out
+++ b/gazelle/python/testdata/relative_imports/BUILD.out
@@ -1,5 +1,7 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")
+# gazelle:resolve py resolved_package //package2:resolved_package
+
py_library(
name = "relative_imports",
srcs = [
diff --git a/gazelle/python/testdata/relative_imports/package2/BUILD.out b/gazelle/python/testdata/relative_imports/package2/BUILD.out
index bbbc9f8..3e03e75 100644
--- a/gazelle/python/testdata/relative_imports/package2/BUILD.out
+++ b/gazelle/python/testdata/relative_imports/package2/BUILD.out
@@ -8,6 +8,6 @@ py_library(
"module4.py",
"subpackage1/module5.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
+ deps = [":resolved_package"],
)
diff --git a/gazelle/python/testdata/relative_imports/package2/module3.py b/gazelle/python/testdata/relative_imports/package2/module3.py
index 74978a0..478dea9 100644
--- a/gazelle/python/testdata/relative_imports/package2/module3.py
+++ b/gazelle/python/testdata/relative_imports/package2/module3.py
@@ -15,6 +15,7 @@
from . import Class1
from .subpackage1.module5 import function5
+import resolved_package
def function3():
c1 = Class1()
diff --git a/gazelle/python/testdata/sibling_imports/pkg/BUILD.out b/gazelle/python/testdata/sibling_imports/pkg/BUILD.out
index edb40a8..cae6c3f 100644
--- a/gazelle/python/testdata/sibling_imports/pkg/BUILD.out
+++ b/gazelle/python/testdata/sibling_imports/pkg/BUILD.out
@@ -7,20 +7,17 @@ py_library(
"a.py",
"b.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
py_test(
name = "test_util",
srcs = ["test_util.py"],
- imports = [".."],
)
py_test(
name = "unit_test",
srcs = ["unit_test.py"],
- imports = [".."],
deps = [
":pkg",
":test_util",
diff --git a/gazelle/python/testdata/simple_library_without_init/foo/BUILD.out b/gazelle/python/testdata/simple_library_without_init/foo/BUILD.out
index 2faa046..8e50095 100644
--- a/gazelle/python/testdata/simple_library_without_init/foo/BUILD.out
+++ b/gazelle/python/testdata/simple_library_without_init/foo/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "foo",
srcs = ["foo.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/simple_test_with_conftest/bar/BUILD.out b/gazelle/python/testdata/simple_test_with_conftest/bar/BUILD.out
index e42c499..4a1204e 100644
--- a/gazelle/python/testdata/simple_test_with_conftest/bar/BUILD.out
+++ b/gazelle/python/testdata/simple_test_with_conftest/bar/BUILD.out
@@ -6,7 +6,6 @@ py_library(
"__init__.py",
"bar.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
@@ -14,14 +13,12 @@ py_library(
name = "conftest",
testonly = True,
srcs = ["conftest.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
py_test(
name = "bar_test",
srcs = ["__test__.py"],
- imports = [".."],
main = "__test__.py",
deps = [
":bar",
diff --git a/gazelle/python/testdata/subdir_sources/foo/BUILD.out b/gazelle/python/testdata/subdir_sources/foo/BUILD.out
index f99857d..9107d2d 100644
--- a/gazelle/python/testdata/subdir_sources/foo/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/foo/BUILD.out
@@ -8,6 +8,5 @@ py_library(
"baz/baz.py",
"foo.py",
],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/subdir_sources/foo/has_build/BUILD.out b/gazelle/python/testdata/subdir_sources/foo/has_build/BUILD.out
index 0ef0cc1..d5196e5 100644
--- a/gazelle/python/testdata/subdir_sources/foo/has_build/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/foo/has_build/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "has_build",
srcs = ["python/my_module.py"],
- imports = ["../.."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/subdir_sources/foo/has_init/BUILD.out b/gazelle/python/testdata/subdir_sources/foo/has_init/BUILD.out
index ce59ee2..de61008 100644
--- a/gazelle/python/testdata/subdir_sources/foo/has_init/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/foo/has_init/BUILD.out
@@ -6,6 +6,5 @@ py_library(
"__init__.py",
"python/my_module.py",
],
- imports = ["../.."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/subdir_sources/foo/has_main/BUILD.out b/gazelle/python/testdata/subdir_sources/foo/has_main/BUILD.out
index 265c08b..1c56f72 100644
--- a/gazelle/python/testdata/subdir_sources/foo/has_main/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/foo/has_main/BUILD.out
@@ -3,14 +3,12 @@ load("@rules_python//python:defs.bzl", "py_binary", "py_library")
py_library(
name = "has_main",
srcs = ["python/my_module.py"],
- imports = ["../.."],
visibility = ["//:__subpackages__"],
)
py_binary(
name = "has_main_bin",
srcs = ["__main__.py"],
- imports = ["../.."],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [":has_main"],
diff --git a/gazelle/python/testdata/subdir_sources/foo/has_test/BUILD.out b/gazelle/python/testdata/subdir_sources/foo/has_test/BUILD.out
index 80739d9..a99278e 100644
--- a/gazelle/python/testdata/subdir_sources/foo/has_test/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/foo/has_test/BUILD.out
@@ -3,14 +3,12 @@ load("@rules_python//python:defs.bzl", "py_library", "py_test")
py_library(
name = "has_test",
srcs = ["python/my_module.py"],
- imports = ["../.."],
visibility = ["//:__subpackages__"],
)
py_test(
name = "has_test_test",
srcs = ["__test__.py"],
- imports = ["../.."],
main = "__test__.py",
deps = [":has_test"],
)
diff --git a/gazelle/python/testdata/subdir_sources/one/BUILD.out b/gazelle/python/testdata/subdir_sources/one/BUILD.out
index f2e5745..b78b650 100644
--- a/gazelle/python/testdata/subdir_sources/one/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/one/BUILD.out
@@ -3,6 +3,5 @@ load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "one",
srcs = ["__init__.py"],
- imports = [".."],
visibility = ["//:__subpackages__"],
)
diff --git a/gazelle/python/testdata/subdir_sources/one/two/BUILD.out b/gazelle/python/testdata/subdir_sources/one/two/BUILD.out
index f632eed..8f0ac17 100644
--- a/gazelle/python/testdata/subdir_sources/one/two/BUILD.out
+++ b/gazelle/python/testdata/subdir_sources/one/two/BUILD.out
@@ -6,7 +6,6 @@ py_library(
"__init__.py",
"three.py",
],
- imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = ["//foo"],
)
diff --git a/gazelle/python/testdata/with_nested_import_statements/BUILD.out b/gazelle/python/testdata/with_nested_import_statements/BUILD.out
index 45bf265..c54bea7 100644
--- a/gazelle/python/testdata/with_nested_import_statements/BUILD.out
+++ b/gazelle/python/testdata/with_nested_import_statements/BUILD.out
@@ -4,5 +4,5 @@ py_library(
name = "with_nested_import_statements",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
- deps = ["@gazelle_python_test_boto3//:pkg"],
+ deps = ["@gazelle_python_test//boto3"],
)
diff --git a/gazelle/python/testdata/with_third_party_requirements/BUILD.out b/gazelle/python/testdata/with_third_party_requirements/BUILD.out
index 2a97d8b..c9330d9 100644
--- a/gazelle/python/testdata/with_third_party_requirements/BUILD.out
+++ b/gazelle/python/testdata/with_third_party_requirements/BUILD.out
@@ -9,9 +9,9 @@ py_library(
],
visibility = ["//:__subpackages__"],
deps = [
- "@gazelle_python_test_baz//:pkg",
- "@gazelle_python_test_boto3//:pkg",
- "@gazelle_python_test_djangorestframework//:pkg",
+ "@gazelle_python_test//baz",
+ "@gazelle_python_test//boto3",
+ "@gazelle_python_test//djangorestframework",
],
)
@@ -20,5 +20,5 @@ py_binary(
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
- deps = ["@gazelle_python_test_baz//:pkg"],
+ deps = ["@gazelle_python_test//baz"],
)
diff --git a/gazelle/python/testdata/with_third_party_requirements_from_imports/BUILD.out b/gazelle/python/testdata/with_third_party_requirements_from_imports/BUILD.out
index 577f167..9d6904f 100644
--- a/gazelle/python/testdata/with_third_party_requirements_from_imports/BUILD.out
+++ b/gazelle/python/testdata/with_third_party_requirements_from_imports/BUILD.out
@@ -8,8 +8,8 @@ py_library(
],
visibility = ["//:__subpackages__"],
deps = [
- "@gazelle_python_test_google_cloud_aiplatform//:pkg",
- "@gazelle_python_test_google_cloud_storage//:pkg",
+ "@gazelle_python_test//google_cloud_aiplatform",
+ "@gazelle_python_test//google_cloud_storage",
],
)
@@ -20,6 +20,6 @@ py_binary(
visibility = ["//:__subpackages__"],
deps = [
":with_third_party_requirements_from_imports",
- "@gazelle_python_test_google_cloud_aiplatform//:pkg",
+ "@gazelle_python_test//google_cloud_aiplatform",
],
)
diff --git a/gazelle/pythonconfig/BUILD.bazel b/gazelle/pythonconfig/BUILD.bazel
index d0f1690..d80902e 100644
--- a/gazelle/pythonconfig/BUILD.bazel
+++ b/gazelle/pythonconfig/BUILD.bazel
@@ -18,7 +18,7 @@ go_library(
go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
- deps = [":pythonconfig"],
+ embed = [":pythonconfig"],
)
filegroup(
diff --git a/gazelle/pythonconfig/pythonconfig.go b/gazelle/pythonconfig/pythonconfig.go
index c7cd7c1..09d308a 100644
--- a/gazelle/pythonconfig/pythonconfig.go
+++ b/gazelle/pythonconfig/pythonconfig.go
@@ -50,6 +50,10 @@ const (
// GenerationMode represents the directive that controls the target generation
// mode. See below for the GenerationModeType constants.
GenerationMode = "python_generation_mode"
+ // GenerationModePerFileIncludeInit represents the directive that augments
+ // the "per_file" GenerationMode by including the package's __init__.py file.
+ // This is a boolean directive.
+ GenerationModePerFileIncludeInit = "python_generation_mode_per_file_include_init"
// LibraryNamingConvention represents the directive that controls the
// py_library naming convention. It interpolates $package_name$ with the
// Bazel package name. E.g. if the Bazel package name is `foo`, setting this
@@ -78,6 +82,7 @@ const (
// GenerationModeProject defines the mode in which a coarse-grained target will
// be generated englobing sub-directories containing Python files.
GenerationModeProject GenerationModeType = "project"
+ GenerationModeFile GenerationModeType = "file"
)
const (
@@ -121,14 +126,16 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest
- excludedPatterns *singlylinkedlist.List
- ignoreFiles map[string]struct{}
- ignoreDependencies map[string]struct{}
- validateImportStatements bool
- coarseGrainedGeneration bool
- libraryNamingConvention string
- binaryNamingConvention string
- testNamingConvention string
+ excludedPatterns *singlylinkedlist.List
+ ignoreFiles map[string]struct{}
+ ignoreDependencies map[string]struct{}
+ validateImportStatements bool
+ coarseGrainedGeneration bool
+ perFileGeneration bool
+ perFileGenerationIncludeInit bool
+ libraryNamingConvention string
+ binaryNamingConvention string
+ testNamingConvention string
}
// New creates a new Config.
@@ -137,17 +144,19 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
- extensionEnabled: true,
- repoRoot: repoRoot,
- pythonProjectRoot: pythonProjectRoot,
- excludedPatterns: singlylinkedlist.New(),
- ignoreFiles: make(map[string]struct{}),
- ignoreDependencies: make(map[string]struct{}),
- validateImportStatements: true,
- coarseGrainedGeneration: false,
- libraryNamingConvention: packageNameNamingConventionSubstitution,
- binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
- testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
+ extensionEnabled: true,
+ repoRoot: repoRoot,
+ pythonProjectRoot: pythonProjectRoot,
+ excludedPatterns: singlylinkedlist.New(),
+ ignoreFiles: make(map[string]struct{}),
+ ignoreDependencies: make(map[string]struct{}),
+ validateImportStatements: true,
+ coarseGrainedGeneration: false,
+ perFileGeneration: false,
+ perFileGenerationIncludeInit: false,
+ libraryNamingConvention: packageNameNamingConventionSubstitution,
+ binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
+ testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
}
}
@@ -160,18 +169,20 @@ func (c *Config) Parent() *Config {
// current Config and sets itself as the parent to the child.
func (c *Config) NewChild() *Config {
return &Config{
- parent: c,
- extensionEnabled: c.extensionEnabled,
- repoRoot: c.repoRoot,
- pythonProjectRoot: c.pythonProjectRoot,
- excludedPatterns: c.excludedPatterns,
- ignoreFiles: make(map[string]struct{}),
- ignoreDependencies: make(map[string]struct{}),
- validateImportStatements: c.validateImportStatements,
- coarseGrainedGeneration: c.coarseGrainedGeneration,
- libraryNamingConvention: c.libraryNamingConvention,
- binaryNamingConvention: c.binaryNamingConvention,
- testNamingConvention: c.testNamingConvention,
+ parent: c,
+ extensionEnabled: c.extensionEnabled,
+ repoRoot: c.repoRoot,
+ pythonProjectRoot: c.pythonProjectRoot,
+ excludedPatterns: c.excludedPatterns,
+ ignoreFiles: make(map[string]struct{}),
+ ignoreDependencies: make(map[string]struct{}),
+ validateImportStatements: c.validateImportStatements,
+ coarseGrainedGeneration: c.coarseGrainedGeneration,
+ perFileGeneration: c.perFileGeneration,
+ perFileGenerationIncludeInit: c.perFileGenerationIncludeInit,
+ libraryNamingConvention: c.libraryNamingConvention,
+ binaryNamingConvention: c.binaryNamingConvention,
+ testNamingConvention: c.testNamingConvention,
}
}
@@ -228,15 +239,16 @@ func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
}
sanitizedDistribution := SanitizeDistribution(distributionName)
- if gazelleManifest.PipRepository != nil && gazelleManifest.PipRepository.UsePipRepositoryAliases {
- // @<repository_name>//<distribution_name>
- lbl := label.New(distributionRepositoryName, sanitizedDistribution, sanitizedDistribution)
+ if repo := gazelleManifest.PipRepository; repo != nil && (repo.UsePipRepositoryAliases != nil && *repo.UsePipRepositoryAliases == false) {
+ // TODO @aignas 2023-10-31: to be removed later.
+ // @<repository_name>_<distribution_name>//:pkg
+ distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
+ lbl := label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}
- // @<repository_name>_<distribution_name>//:pkg
- distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
- lbl := label.New(distributionRepositoryName, "", "pkg")
+ // @<repository_name>//<distribution_name>
+ lbl := label.New(distributionRepositoryName, sanitizedDistribution, sanitizedDistribution)
return lbl.String(), true
}
}
@@ -327,6 +339,30 @@ func (c *Config) CoarseGrainedGeneration() bool {
return c.coarseGrainedGeneration
}
+// SetPerFileGneration sets whether a separate py_library target should be
+// generated for each file.
+func (c *Config) SetPerFileGeneration(perFile bool) {
+ c.perFileGeneration = perFile
+}
+
+// PerFileGeneration returns whether a separate py_library target should be
+// generated for each file.
+func (c *Config) PerFileGeneration() bool {
+ return c.perFileGeneration
+}
+
+// SetPerFileGenerationIncludeInit sets whether py_library targets should
+// include __init__.py files when PerFileGeneration() is true.
+func (c *Config) SetPerFileGenerationIncludeInit(includeInit bool) {
+ c.perFileGenerationIncludeInit = includeInit
+}
+
+// PerFileGenerationIncludeInit returns whether py_library targets should
+// include __init__.py files when PerFileGeneration() is true.
+func (c *Config) PerFileGenerationIncludeInit() bool {
+ return c.perFileGenerationIncludeInit
+}
+
// SetLibraryNamingConvention sets the py_library target naming convention.
func (c *Config) SetLibraryNamingConvention(libraryNamingConvention string) {
c.libraryNamingConvention = libraryNamingConvention
diff --git a/gazelle/pythonconfig/pythonconfig_test.go b/gazelle/pythonconfig/pythonconfig_test.go
index 1512eb9..bf31106 100644
--- a/gazelle/pythonconfig/pythonconfig_test.go
+++ b/gazelle/pythonconfig/pythonconfig_test.go
@@ -2,8 +2,6 @@ package pythonconfig
import (
"testing"
-
- "github.com/bazelbuild/rules_python/gazelle/pythonconfig"
)
func TestDistributionSanitizing(t *testing.T) {
@@ -19,7 +17,7 @@ func TestDistributionSanitizing(t *testing.T) {
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
- got := pythonconfig.SanitizeDistribution(tc.input)
+ got := SanitizeDistribution(tc.input)
if tc.want != got {
t.Fatalf("expected %q, got %q", tc.want, got)
}
diff --git a/internal_deps.bzl b/internal_deps.bzl
index f50d2bf..3835cd6 100644
--- a/internal_deps.bzl
+++ b/internal_deps.bzl
@@ -14,17 +14,30 @@
"""Dependencies that are needed for rules_python tests and tools."""
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive", _http_file = "http_file")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+def http_archive(name, **kwargs):
+ maybe(
+ _http_archive,
+ name = name,
+ **kwargs
+ )
+
+def http_file(name, **kwargs):
+ maybe(
+ _http_file,
+ name = name,
+ **kwargs
+ )
+
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,
+ http_archive(
name = "bazel_skylib",
sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d",
urls = [
@@ -33,8 +46,7 @@ def rules_python_internal_deps():
],
)
- maybe(
- http_archive,
+ http_archive(
name = "rules_pkg",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.7.0/rules_pkg-0.7.0.tar.gz",
@@ -43,16 +55,14 @@ def rules_python_internal_deps():
sha256 = "8a298e832762eda1830597d64fe7db58178aa84cd5926d76d5b744d6558941c2",
)
- maybe(
- http_archive,
+ http_archive(
name = "rules_testing",
sha256 = "8df0a8eb21739ea4b0a03f5dc79e68e245a45c076cfab404b940cc205cb62162",
strip_prefix = "rules_testing-0.4.0",
url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.4.0/rules_testing-v0.4.0.tar.gz",
)
- maybe(
- http_archive,
+ http_archive(
name = "rules_license",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz",
@@ -61,28 +71,27 @@ def rules_python_internal_deps():
sha256 = "4531deccb913639c30e5c7512a054d5d875698daeb75d8cf90f284375fe7c360",
)
- maybe(
- http_archive,
+ http_archive(
name = "io_bazel_stardoc",
- url = "https://github.com/bazelbuild/stardoc/archive/6f274e903009158504a9d9130d7f7d5f3e9421ed.tar.gz",
- sha256 = "b5d6891f869d5b5a224316ec4dd9e9d481885a9b1a1c81eb846e20180156f2fa",
- strip_prefix = "stardoc-6f274e903009158504a9d9130d7f7d5f3e9421ed",
+ sha256 = "62bd2e60216b7a6fec3ac79341aa201e0956477e7c8f6ccc286f279ad1d96432",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/stardoc/releases/download/0.6.2/stardoc-0.6.2.tar.gz",
+ "https://github.com/bazelbuild/stardoc/releases/download/0.6.2/stardoc-0.6.2.tar.gz",
+ ],
)
# The below two deps are required for the integration test with bazel
# gazelle. Maybe the test should be moved to the `gazelle` workspace?
- maybe(
- http_archive,
+ http_archive(
name = "io_bazel_rules_go",
- sha256 = "6dc2da7ab4cf5d7bfc7c949776b1b7c733f05e56edc4bcd9022bb249d2e2a996",
+ sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.39.1/rules_go-v0.39.1.zip",
- "https://github.com/bazelbuild/rules_go/releases/download/v0.39.1/rules_go-v0.39.1.zip",
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
+ "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
],
)
- maybe(
- http_archive,
+ http_archive(
name = "bazel_gazelle",
sha256 = "727f3e4edd96ea20c29e8c2ca9e8d2af724d8c7778e7923a854b2c80952bc405",
urls = [
@@ -92,78 +101,79 @@ def rules_python_internal_deps():
)
# Test data for WHL tool testing.
- maybe(
- http_file,
+ http_file(
name = "futures_2_2_0_whl",
downloaded_file_path = "futures-2.2.0-py2.py3-none-any.whl",
sha256 = "9fd22b354a4c4755ad8c7d161d93f5026aca4cfe999bd2e53168f14765c02cd6",
- # From https://pypi.python.org/pypi/futures/2.2.0
+ # From https://pypi.org/pypi/futures/2.2.0
urls = [
- "https://mirror.bazel.build/pypi.python.org/packages/d7/1d/68874943aa37cf1c483fc61def813188473596043158faa6511c04a038b4/futures-2.2.0-py2.py3-none-any.whl",
- "https://pypi.python.org/packages/d7/1d/68874943aa37cf1c483fc61def813188473596043158faa6511c04a038b4/futures-2.2.0-py2.py3-none-any.whl",
+ "https://mirror.bazel.build/pypi.org/packages/d7/1d/68874943aa37cf1c483fc61def813188473596043158faa6511c04a038b4/futures-2.2.0-py2.py3-none-any.whl",
+ "https://pypi.org/packages/d7/1d/68874943aa37cf1c483fc61def813188473596043158faa6511c04a038b4/futures-2.2.0-py2.py3-none-any.whl",
],
)
- maybe(
- http_file,
+ http_file(
name = "futures_3_1_1_whl",
downloaded_file_path = "futures-3.1.1-py2-none-any.whl",
sha256 = "c4884a65654a7c45435063e14ae85280eb1f111d94e542396717ba9828c4337f",
- # From https://pypi.python.org/pypi/futures
+ # From https://pypi.org/pypi/futures
urls = [
- "https://mirror.bazel.build/pypi.python.org/packages/a6/1c/72a18c8c7502ee1b38a604a5c5243aa8c2a64f4bba4e6631b1b8972235dd/futures-3.1.1-py2-none-any.whl",
- "https://pypi.python.org/packages/a6/1c/72a18c8c7502ee1b38a604a5c5243aa8c2a64f4bba4e6631b1b8972235dd/futures-3.1.1-py2-none-any.whl",
+ "https://mirror.bazel.build/pypi.org/packages/a6/1c/72a18c8c7502ee1b38a604a5c5243aa8c2a64f4bba4e6631b1b8972235dd/futures-3.1.1-py2-none-any.whl",
+ "https://pypi.org/packages/a6/1c/72a18c8c7502ee1b38a604a5c5243aa8c2a64f4bba4e6631b1b8972235dd/futures-3.1.1-py2-none-any.whl",
],
)
- maybe(
- http_file,
+ http_file(
name = "google_cloud_language_whl",
downloaded_file_path = "google_cloud_language-0.29.0-py2.py3-none-any.whl",
sha256 = "a2dd34f0a0ebf5705dcbe34bd41199b1d0a55c4597d38ed045bd183361a561e9",
- # From https://pypi.python.org/pypi/google-cloud-language
+ # From https://pypi.org/pypi/google-cloud-language
urls = [
- "https://mirror.bazel.build/pypi.python.org/packages/6e/86/cae57e4802e72d9e626ee5828ed5a646cf4016b473a4a022f1038dba3460/google_cloud_language-0.29.0-py2.py3-none-any.whl",
- "https://pypi.python.org/packages/6e/86/cae57e4802e72d9e626ee5828ed5a646cf4016b473a4a022f1038dba3460/google_cloud_language-0.29.0-py2.py3-none-any.whl",
+ "https://mirror.bazel.build/pypi.org/packages/6e/86/cae57e4802e72d9e626ee5828ed5a646cf4016b473a4a022f1038dba3460/google_cloud_language-0.29.0-py2.py3-none-any.whl",
+ "https://pypi.org/packages/6e/86/cae57e4802e72d9e626ee5828ed5a646cf4016b473a4a022f1038dba3460/google_cloud_language-0.29.0-py2.py3-none-any.whl",
],
)
- maybe(
- http_file,
+ http_file(
name = "grpc_whl",
downloaded_file_path = "grpcio-1.6.0-cp27-cp27m-manylinux1_i686.whl",
sha256 = "c232d6d168cb582e5eba8e1c0da8d64b54b041dd5ea194895a2fe76050916561",
- # From https://pypi.python.org/pypi/grpcio/1.6.0
+ # From https://pypi.org/pypi/grpcio/1.6.0
urls = [
- "https://mirror.bazel.build/pypi.python.org/packages/c6/28/67651b4eabe616b27472c5518f9b2aa3f63beab8f62100b26f05ac428639/grpcio-1.6.0-cp27-cp27m-manylinux1_i686.whl",
- "https://pypi.python.org/packages/c6/28/67651b4eabe616b27472c5518f9b2aa3f63beab8f62100b26f05ac428639/grpcio-1.6.0-cp27-cp27m-manylinux1_i686.whl",
+ "https://mirror.bazel.build/pypi.org/packages/c6/28/67651b4eabe616b27472c5518f9b2aa3f63beab8f62100b26f05ac428639/grpcio-1.6.0-cp27-cp27m-manylinux1_i686.whl",
+ "https://pypi.org/packages/c6/28/67651b4eabe616b27472c5518f9b2aa3f63beab8f62100b26f05ac428639/grpcio-1.6.0-cp27-cp27m-manylinux1_i686.whl",
],
)
- maybe(
- http_file,
+ http_file(
name = "mock_whl",
downloaded_file_path = "mock-2.0.0-py2.py3-none-any.whl",
sha256 = "5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
- # From https://pypi.python.org/pypi/mock
+ # From https://pypi.org/pypi/mock
urls = [
- "https://mirror.bazel.build/pypi.python.org/packages/e6/35/f187bdf23be87092bd0f1200d43d23076cee4d0dec109f195173fd3ebc79/mock-2.0.0-py2.py3-none-any.whl",
- "https://pypi.python.org/packages/e6/35/f187bdf23be87092bd0f1200d43d23076cee4d0dec109f195173fd3ebc79/mock-2.0.0-py2.py3-none-any.whl",
+ "https://mirror.bazel.build/pypi.org/packages/e6/35/f187bdf23be87092bd0f1200d43d23076cee4d0dec109f195173fd3ebc79/mock-2.0.0-py2.py3-none-any.whl",
+ "https://pypi.org/packages/e6/35/f187bdf23be87092bd0f1200d43d23076cee4d0dec109f195173fd3ebc79/mock-2.0.0-py2.py3-none-any.whl",
],
)
- maybe(
- http_archive,
- name = "build_bazel_integration_testing",
+ http_archive(
+ name = "rules_bazel_integration_test",
+ sha256 = "6e65d497c68f5794349bfa004369e144063686ce1ebd0227717cd23285be45ef",
urls = [
- "https://github.com/bazelbuild/bazel-integration-testing/archive/165440b2dbda885f8d1ccb8d0f417e6cf8c54f17.zip",
+ "https://github.com/bazel-contrib/rules_bazel_integration_test/releases/download/v0.20.0/rules_bazel_integration_test.v0.20.0.tar.gz",
],
- strip_prefix = "bazel-integration-testing-165440b2dbda885f8d1ccb8d0f417e6cf8c54f17",
- sha256 = "2401b1369ef44cc42f91dc94443ef491208dbd06da1e1e10b702d8c189f098e3",
)
- maybe(
- http_archive,
+ # Dependency of rules_bazel_integration_test.
+ http_archive(
+ name = "cgrindel_bazel_starlib",
+ sha256 = "9090280a9cff7322e7c22062506b3273a2e880ca464e520b5c77fdfbed4e8805",
+ urls = [
+ "https://github.com/cgrindel/bazel-starlib/releases/download/v0.18.1/bazel-starlib.v0.18.1.tar.gz",
+ ],
+ )
+
+ http_archive(
name = "rules_proto",
sha256 = "dc3fb206a2cb3441b485eb1e423165b231235a1ea9b031b4433cf7bc1fa460dd",
strip_prefix = "rules_proto-5.3.0-21.7",
@@ -172,8 +182,7 @@ def rules_python_internal_deps():
],
)
- maybe(
- http_archive,
+ http_archive(
name = "com_google_protobuf",
sha256 = "75be42bd736f4df6d702a0e4e4d30de9ee40eac024c4b845d17ae4cc831fe4ae",
strip_prefix = "protobuf-21.7",
@@ -182,3 +191,33 @@ def rules_python_internal_deps():
"https://github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
],
)
+
+ # Needed for stardoc
+ http_archive(
+ name = "rules_java",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_java/releases/download/6.3.0/rules_java-6.3.0.tar.gz",
+ "https://github.com/bazelbuild/rules_java/releases/download/6.3.0/rules_java-6.3.0.tar.gz",
+ ],
+ sha256 = "29ba147c583aaf5d211686029842c5278e12aaea86f66bd4a9eb5e525b7f2701",
+ )
+
+ RULES_JVM_EXTERNAL_TAG = "5.2"
+ RULES_JVM_EXTERNAL_SHA = "f86fd42a809e1871ca0aabe89db0d440451219c3ce46c58da240c7dcdc00125f"
+ http_archive(
+ name = "rules_jvm_external",
+ patch_args = ["-p1"],
+ patches = ["@io_bazel_stardoc//:rules_jvm_external.patch"],
+ strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
+ sha256 = RULES_JVM_EXTERNAL_SHA,
+ url = "https://github.com/bazelbuild/rules_jvm_external/releases/download/%s/rules_jvm_external-%s.tar.gz" % (RULES_JVM_EXTERNAL_TAG, RULES_JVM_EXTERNAL_TAG),
+ )
+
+ http_archive(
+ name = "rules_license",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz",
+ "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz",
+ ],
+ sha256 = "4531deccb913639c30e5c7512a054d5d875698daeb75d8cf90f284375fe7c360",
+ )
diff --git a/internal_setup.bzl b/internal_setup.bzl
index c3a7ad4..a80099f 100644
--- a/internal_setup.bzl
+++ b/internal_setup.bzl
@@ -15,24 +15,30 @@
"""Setup for rules_python tests and tools."""
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
-load("@build_bazel_integration_testing//tools:repositories.bzl", "bazel_binaries")
+load("@cgrindel_bazel_starlib//:deps.bzl", "bazel_starlib_dependencies")
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
+load("@rules_bazel_integration_test//bazel_integration_test:deps.bzl", "bazel_integration_test_rules_dependencies")
+load("@rules_bazel_integration_test//bazel_integration_test:repo_defs.bzl", "bazel_binaries")
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
load("//:version.bzl", "SUPPORTED_BAZEL_VERSIONS")
load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
+load("//python/private:internal_config_repo.bzl", "internal_config_repo") # buildifier: disable=bzl-visibility
def rules_python_internal_setup():
"""Setup for rules_python tests and tools."""
+ internal_config_repo(name = "rules_python_internal")
+
# Because we don't use the pip_install rule, we have to call this to fetch its deps
pip_install_dependencies()
- # Depend on the Bazel binaries for running bazel-in-bazel tests
- bazel_binaries(versions = SUPPORTED_BAZEL_VERSIONS)
-
bazel_skylib_workspace()
rules_proto_dependencies()
rules_proto_toolchains()
protobuf_deps()
+
+ bazel_integration_test_rules_dependencies()
+ bazel_starlib_dependencies()
+ bazel_binaries(versions = SUPPORTED_BAZEL_VERSIONS)
diff --git a/python/BUILD.bazel b/python/BUILD.bazel
index c5f2580..1ab59d5 100644
--- a/python/BUILD.bazel
+++ b/python/BUILD.bazel
@@ -36,6 +36,8 @@ filegroup(
"//python/cc:distribution",
"//python/config_settings:distribution",
"//python/constraints:distribution",
+ "//python/entry_points:distribution",
+ "//python/extensions:distribution",
"//python/private:distribution",
"//python/runfiles:distribution",
],
@@ -70,6 +72,32 @@ bzl_library(
)
bzl_library(
+ name = "packaging_bzl",
+ srcs = ["packaging.bzl"],
+ deps = [
+ ":py_binary_bzl",
+ "//python/private:py_package.bzl",
+ "//python/private:py_wheel_bzl",
+ "//python/private:py_wheel_normalize_pep440.bzl",
+ "//python/private:stamp_bzl",
+ "//python/private:util_bzl",
+ ],
+)
+
+bzl_library(
+ name = "pip_bzl",
+ srcs = ["pip.bzl"],
+ deps = [
+ "//python/pip_install:pip_repository_bzl",
+ "//python/pip_install:repositories_bzl",
+ "//python/pip_install:requirements_bzl",
+ "//python/private:bzlmod_enabled_bzl",
+ "//python/private:full_version_bzl",
+ "//python/private:render_pkg_aliases_bzl",
+ ],
+)
+
+bzl_library(
name = "proto_bzl",
srcs = [
"proto.bzl",
@@ -83,7 +111,12 @@ bzl_library(
bzl_library(
name = "py_binary_bzl",
srcs = ["py_binary.bzl"],
- deps = ["//python/private:util_bzl"],
+ deps = [
+ "//python/private:register_extension_info_bzl",
+ "//python/private:util_bzl",
+ "//python/private/common:py_binary_macro_bazel_bzl",
+ "@rules_python_internal//:rules_python_config_bzl",
+ ],
)
bzl_library(
@@ -100,37 +133,85 @@ bzl_library(
bzl_library(
name = "py_info_bzl",
srcs = ["py_info.bzl"],
- deps = ["//python/private:reexports_bzl"],
+ deps = [
+ "//python/private:reexports_bzl",
+ "//python/private/common:providers_bzl",
+ "@rules_python_internal//:rules_python_config_bzl",
+ ],
)
bzl_library(
name = "py_library_bzl",
srcs = ["py_library.bzl"],
- deps = ["//python/private:util_bzl"],
+ deps = [
+ "//python/private:register_extension_info_bzl",
+ "//python/private:util_bzl",
+ "//python/private/common:py_library_macro_bazel_bzl",
+ "@rules_python_internal//:rules_python_config_bzl",
+ ],
)
bzl_library(
name = "py_runtime_bzl",
srcs = ["py_runtime.bzl"],
- deps = ["//python/private:util_bzl"],
+ deps = [
+ "//python/private:util_bzl",
+ "//python/private/common:py_runtime_macro_bzl",
+ ],
)
bzl_library(
name = "py_runtime_pair_bzl",
srcs = ["py_runtime_pair.bzl"],
- deps = ["//python/private:bazel_tools_bzl"],
+ deps = [
+ "//python/private:bazel_tools_bzl",
+ "//python/private:py_runtime_pair_macro_bzl",
+ "//python/private:util_bzl",
+ ],
)
bzl_library(
name = "py_runtime_info_bzl",
srcs = ["py_runtime_info.bzl"],
- deps = ["//python/private:reexports_bzl"],
+ deps = [
+ "//python/private:reexports_bzl",
+ "//python/private:util_bzl",
+ "//python/private/common:providers_bzl",
+ ],
)
bzl_library(
name = "py_test_bzl",
srcs = ["py_test.bzl"],
- deps = ["//python/private:util_bzl"],
+ deps = [
+ "//python/private:register_extension_info_bzl",
+ "//python/private:util_bzl",
+ "//python/private/common:py_test_macro_bazel_bzl",
+ "@rules_python_internal//:rules_python_config_bzl",
+ ],
+)
+
+bzl_library(
+ name = "repositories_bzl",
+ srcs = ["repositories.bzl"],
+ deps = [
+ ":versions_bzl",
+ "//python/pip_install:repositories_bzl",
+ "//python/private:auth_bzl",
+ "//python/private:bazel_tools_bzl",
+ "//python/private:bzlmod_enabled_bzl",
+ "//python/private:coverage_deps_bzl",
+ "//python/private:full_version_bzl",
+ "//python/private:internal_config_repo_bzl",
+ "//python/private:toolchains_repo_bzl",
+ "//python/private:which_bzl",
+ ],
+)
+
+bzl_library(
+ name = "versions_bzl",
+ srcs = ["versions.bzl"],
+ visibility = ["//:__subpackages__"],
)
# NOTE: Remember to add bzl_library targets to //tests:bzl_libraries
diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel
index 272ba78..ab4ee8d 100644
--- a/python/config_settings/BUILD.bazel
+++ b/python/config_settings/BUILD.bazel
@@ -5,6 +5,7 @@ filegroup(
name = "distribution",
srcs = glob(["*.bzl"]) + [
"BUILD.bazel",
+ "//python/config_settings/private:distribution",
],
visibility = ["//python:__pkg__"],
)
diff --git a/python/config_settings/private/BUILD.bazel b/python/config_settings/private/BUILD.bazel
index e69de29..aa68c65 100644
--- a/python/config_settings/private/BUILD.bazel
+++ b/python/config_settings/private/BUILD.bazel
@@ -0,0 +1,7 @@
+filegroup(
+ name = "distribution",
+ srcs = glob(["*.bzl"]) + [
+ "BUILD.bazel",
+ ],
+ visibility = ["//python/config_settings:__pkg__"],
+)
diff --git a/python/config_settings/transition.bzl b/python/config_settings/transition.bzl
index 20e03dc..cd54b21 100644
--- a/python/config_settings/transition.bzl
+++ b/python/config_settings/transition.bzl
@@ -17,8 +17,12 @@ them to the desired target platform.
"""
load("@bazel_skylib//lib:dicts.bzl", "dicts")
-load("//python:defs.bzl", _py_binary = "py_binary", _py_test = "py_test")
+load("//python:py_binary.bzl", _py_binary = "py_binary")
+load("//python:py_info.bzl", "PyInfo")
+load("//python:py_runtime_info.bzl", "PyRuntimeInfo")
+load("//python:py_test.bzl", _py_test = "py_test")
load("//python/config_settings/private:py_args.bzl", "py_args")
+load("//python/private:reexports.bzl", "BuiltinPyInfo", "BuiltinPyRuntimeInfo")
def _transition_python_version_impl(_, attr):
return {"//python/config_settings:python_version": str(attr.python_version)}
@@ -59,14 +63,28 @@ def _transition_py_impl(ctx):
for k, v in ctx.attr.env.items():
env[k] = ctx.expand_location(v)
+ if PyInfo in target:
+ py_info = target[PyInfo]
+ elif BuiltinPyInfo in target:
+ py_info = target[BuiltinPyInfo]
+ else:
+ fail("target {} does not have rules_python PyInfo or builtin PyInfo".format(target))
+
+ if PyRuntimeInfo in target:
+ py_runtime_info = target[PyRuntimeInfo]
+ elif BuiltinPyRuntimeInfo in target:
+ py_runtime_info = target[BuiltinPyRuntimeInfo]
+ else:
+ fail("target {} does not have rules_python PyRuntimeInfo or builtin PyRuntimeInfo".format(target))
+
providers = [
DefaultInfo(
executable = executable,
files = depset([zipfile_symlink] if zipfile_symlink else [], transitive = [target[DefaultInfo].files]),
runfiles = ctx.runfiles([zipfile_symlink] if zipfile_symlink else []).merge(target[DefaultInfo].default_runfiles),
),
- target[PyInfo],
- target[PyRuntimeInfo],
+ py_info,
+ py_runtime_info,
# Ensure that the binary we're wrapping is included in code coverage.
coverage_common.instrumented_files_info(
ctx,
@@ -124,16 +142,33 @@ _COMMON_ATTRS = {
),
}
+_PY_TEST_ATTRS = {
+ # Magic attribute to help C++ coverage work. There's no
+ # docs about this; see TestActionBuilder.java
+ "_collect_cc_coverage": attr.label(
+ default = "@bazel_tools//tools/test:collect_cc_coverage",
+ executable = True,
+ cfg = "exec",
+ ),
+ # Magic attribute to make coverage work. There's no
+ # docs about this; see TestActionBuilder.java
+ "_lcov_merger": attr.label(
+ default = configuration_field(fragment = "coverage", name = "output_generator"),
+ executable = True,
+ cfg = "exec",
+ ),
+}
+
_transition_py_binary = rule(
_transition_py_impl,
- attrs = _COMMON_ATTRS,
+ attrs = _COMMON_ATTRS | _PY_TEST_ATTRS,
cfg = _transition_python_version,
executable = True,
)
_transition_py_test = rule(
_transition_py_impl,
- attrs = _COMMON_ATTRS,
+ attrs = _COMMON_ATTRS | _PY_TEST_ATTRS,
cfg = _transition_python_version,
test = True,
)
@@ -151,7 +186,6 @@ def _py_rule(rule_impl, transition_rule, name, python_version, **kwargs):
# https://bazel.build/reference/be/common-definitions#common-attributes
compatible_with = kwargs.pop("compatible_with", None)
deprecation = kwargs.pop("deprecation", None)
- distribs = kwargs.pop("distribs", None)
exec_compatible_with = kwargs.pop("exec_compatible_with", None)
exec_properties = kwargs.pop("exec_properties", None)
features = kwargs.pop("features", None)
@@ -165,7 +199,6 @@ def _py_rule(rule_impl, transition_rule, name, python_version, **kwargs):
common_attrs = {
"compatible_with": compatible_with,
"deprecation": deprecation,
- "distribs": distribs,
"exec_compatible_with": exec_compatible_with,
"exec_properties": exec_properties,
"features": features,
diff --git a/python/defs.bzl b/python/defs.bzl
index 3fb6b5b..bd89f5b 100644
--- a/python/defs.bzl
+++ b/python/defs.bzl
@@ -15,7 +15,7 @@
load("@bazel_tools//tools/python:srcs_version.bzl", _find_requirements = "find_requirements")
load("//python:py_binary.bzl", _py_binary = "py_binary")
-load("//python:py_info.bzl", internal_PyInfo = "PyInfo")
+load("//python:py_info.bzl", _PyInfo = "PyInfo")
load("//python:py_library.bzl", _py_library = "py_library")
load("//python:py_runtime.bzl", _py_runtime = "py_runtime")
load("//python:py_runtime_info.bzl", internal_PyRuntimeInfo = "PyRuntimeInfo")
@@ -26,9 +26,7 @@ load(":py_import.bzl", _py_import = "py_import")
# Patching placeholder: end of loads
-# Exports of native-defined providers.
-
-PyInfo = internal_PyInfo
+PyInfo = _PyInfo
PyRuntimeInfo = internal_PyRuntimeInfo
diff --git a/python/entry_points/BUILD.bazel b/python/entry_points/BUILD.bazel
new file mode 100644
index 0000000..d45fb18
--- /dev/null
+++ b/python/entry_points/BUILD.bazel
@@ -0,0 +1,41 @@
+# 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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+exports_files(
+ [
+ "py_console_script_binary.bzl",
+ ],
+ visibility = ["//docs:__subpackages__"],
+)
+
+bzl_library(
+ name = "py_console_script_binary_bzl",
+ srcs = [":py_console_script_binary.bzl"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//python/private:py_console_script_binary_bzl",
+ ],
+)
+
+filegroup(
+ name = "distribution",
+ srcs = glob([
+ "*.bzl",
+ ]) + [
+ "BUILD.bazel",
+ ],
+ visibility = ["//python:__subpackages__"],
+)
diff --git a/python/entry_points/py_console_script_binary.bzl b/python/entry_points/py_console_script_binary.bzl
new file mode 100644
index 0000000..c61d44a
--- /dev/null
+++ b/python/entry_points/py_console_script_binary.bzl
@@ -0,0 +1,24 @@
+# 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.
+
+"""
+Creates an executable (a non-test binary) for console_script entry points.
+
+```{include} /_includes/py_console_script_binary.md
+```
+"""
+
+load("//python/private:py_console_script_binary.bzl", _py_console_script_binary = "py_console_script_binary")
+
+py_console_script_binary = _py_console_script_binary
diff --git a/python/extensions/BUILD.bazel b/python/extensions/BUILD.bazel
index 7f6873d..88e3984 100644
--- a/python/extensions/BUILD.bazel
+++ b/python/extensions/BUILD.bazel
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
@@ -19,5 +21,19 @@ licenses(["notice"])
filegroup(
name = "distribution",
srcs = glob(["**"]),
- visibility = ["//extensions:__pkg__"],
+ visibility = ["//python:__pkg__"],
+)
+
+bzl_library(
+ name = "pip_bzl",
+ srcs = ["pip.bzl"],
+ visibility = ["//:__subpackages__"],
+ deps = ["//python/private/bzlmod:pip_bzl"],
+)
+
+bzl_library(
+ name = "python_bzl",
+ srcs = ["python.bzl"],
+ visibility = ["//:__subpackages__"],
+ deps = ["//python/private/bzlmod:python_bzl"],
)
diff --git a/python/extensions/pip.bzl b/python/extensions/pip.bzl
index add69a4..a69ee34 100644
--- a/python/extensions/pip.bzl
+++ b/python/extensions/pip.bzl
@@ -14,484 +14,6 @@
"pip module extension for use with bzlmod"
-load("@pythons_hub//:interpreters.bzl", "DEFAULT_PYTHON_VERSION", "INTERPRETER_LABELS")
-load("@rules_python//python:pip.bzl", "whl_library_alias")
-load(
- "@rules_python//python/pip_install:pip_repository.bzl",
- "locked_requirements_label",
- "pip_hub_repository_bzlmod",
- "pip_repository_attrs",
- "pip_repository_bzlmod",
- "use_isolated",
- "whl_library",
-)
-load("@rules_python//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
-load("//python/private:normalize_name.bzl", "normalize_name")
-load("//python/private:version_label.bzl", "version_label")
+load("//python/private/bzlmod:pip.bzl", _pip = "pip")
-def _whl_mods_impl(mctx):
- """Implementation of the pip.whl_mods tag class.
-
- This creates the JSON files used to modify the creation of different wheels.
-"""
- whl_mods_dict = {}
- for mod in mctx.modules:
- for whl_mod_attr in mod.tags.whl_mods:
- if whl_mod_attr.hub_name not in whl_mods_dict.keys():
- whl_mods_dict[whl_mod_attr.hub_name] = {whl_mod_attr.whl_name: whl_mod_attr}
- elif whl_mod_attr.whl_name in whl_mods_dict[whl_mod_attr.hub_name].keys():
- # We cannot have the same wheel name in the same hub, as we
- # will create the same JSON file name.
- fail("""\
-Found same whl_name '{}' in the same hub '{}', please use a different hub_name.""".format(
- whl_mod_attr.whl_name,
- whl_mod_attr.hub_name,
- ))
- else:
- whl_mods_dict[whl_mod_attr.hub_name][whl_mod_attr.whl_name] = whl_mod_attr
-
- for hub_name, whl_maps in whl_mods_dict.items():
- whl_mods = {}
-
- # create a struct that we can pass to the _whl_mods_repo rule
- # to create the different JSON files.
- for whl_name, mods in whl_maps.items():
- build_content = mods.additive_build_content
- if mods.additive_build_content_file != None and mods.additive_build_content != "":
- fail("""\
-You cannot use both the additive_build_content and additive_build_content_file arguments at the same time.
-""")
- elif mods.additive_build_content_file != None:
- build_content = mctx.read(mods.additive_build_content_file)
-
- whl_mods[whl_name] = json.encode(struct(
- additive_build_content = build_content,
- copy_files = mods.copy_files,
- copy_executables = mods.copy_executables,
- data = mods.data,
- data_exclude_glob = mods.data_exclude_glob,
- srcs_exclude_glob = mods.srcs_exclude_glob,
- ))
-
- _whl_mods_repo(
- name = hub_name,
- whl_mods = whl_mods,
- )
-
-def _create_versioned_pip_and_whl_repos(module_ctx, pip_attr, whl_map):
- python_interpreter_target = pip_attr.python_interpreter_target
-
- # if we do not have the python_interpreter set in the attributes
- # we programtically find it.
- hub_name = pip_attr.hub_name
- if python_interpreter_target == None:
- python_name = "python_" + version_label(pip_attr.python_version, sep = "_")
- if python_name not in INTERPRETER_LABELS.keys():
- fail((
- "Unable to find interpreter for pip hub '{hub_name}' for " +
- "python_version={version}: Make sure a corresponding " +
- '`python.toolchain(python_version="{version}")` call exists'
- ).format(
- hub_name = hub_name,
- version = pip_attr.python_version,
- ))
- python_interpreter_target = INTERPRETER_LABELS[python_name]
-
- pip_name = "{}_{}".format(
- hub_name,
- version_label(pip_attr.python_version),
- )
- requrements_lock = locked_requirements_label(module_ctx, pip_attr)
-
- # Parse the requirements file directly in starlark to get the information
- # needed for the whl_libary declarations below. This is needed to contain
- # the pip_repository logic to a single module extension.
- requirements_lock_content = module_ctx.read(requrements_lock)
- parse_result = parse_requirements(requirements_lock_content)
- requirements = parse_result.requirements
- extra_pip_args = pip_attr.extra_pip_args + parse_result.options
-
- # Create the repository where users load the `requirement` macro. Under bzlmod
- # this does not create the install_deps() macro.
- # TODO: we may not need this repository once we have entry points
- # supported. For now a user can access this repository and use
- # the entrypoint functionality.
- pip_repository_bzlmod(
- name = pip_name,
- repo_name = pip_name,
- requirements_lock = pip_attr.requirements_lock,
- )
- if hub_name not in whl_map:
- whl_map[hub_name] = {}
-
- whl_modifications = {}
- if pip_attr.whl_modifications != None:
- for mod, whl_name in pip_attr.whl_modifications.items():
- whl_modifications[whl_name] = mod
-
- # Create a new wheel library for each of the different whls
- for whl_name, requirement_line in requirements:
- # We are not using the "sanitized name" because the user
- # would need to guess what name we modified the whl name
- # to.
- annotation = whl_modifications.get(whl_name)
- whl_name = normalize_name(whl_name)
- whl_library(
- name = "%s_%s" % (pip_name, whl_name),
- requirement = requirement_line,
- repo = pip_name,
- repo_prefix = pip_name + "_",
- annotation = annotation,
- python_interpreter = pip_attr.python_interpreter,
- python_interpreter_target = python_interpreter_target,
- quiet = pip_attr.quiet,
- timeout = pip_attr.timeout,
- isolated = use_isolated(module_ctx, pip_attr),
- extra_pip_args = extra_pip_args,
- download_only = pip_attr.download_only,
- pip_data_exclude = pip_attr.pip_data_exclude,
- enable_implicit_namespace_pkgs = pip_attr.enable_implicit_namespace_pkgs,
- environment = pip_attr.environment,
- )
-
- if whl_name not in whl_map[hub_name]:
- whl_map[hub_name][whl_name] = {}
-
- whl_map[hub_name][whl_name][pip_attr.python_version] = pip_name + "_"
-
-def _pip_impl(module_ctx):
- """Implementation of a class tag that creates the pip hub(s) and corresponding pip spoke, alias and whl repositories.
-
- This implmentation iterates through all of the `pip.parse` calls and creates
- different pip hub repositories based on the "hub_name". Each of the
- pip calls create spoke repos that uses a specific Python interpreter.
-
- In a MODULES.bazel file we have:
-
- pip.parse(
- hub_name = "pip",
- python_version = 3.9,
- requirements_lock = "//:requirements_lock_3_9.txt",
- requirements_windows = "//:requirements_windows_3_9.txt",
- )
- pip.parse(
- hub_name = "pip",
- python_version = 3.10,
- requirements_lock = "//:requirements_lock_3_10.txt",
- requirements_windows = "//:requirements_windows_3_10.txt",
- )
-
- For instance, we have a hub with the name of "pip".
- A repository named the following is created. It is actually called last when
- all of the pip spokes are collected.
-
- - @@rules_python~override~pip~pip
-
- As shown in the example code above we have the following.
- Two different pip.parse statements exist in MODULE.bazel provide the hub_name "pip".
- These definitions create two different pip spoke repositories that are
- related to the hub "pip".
- One spoke uses Python 3.9 and the other uses Python 3.10. This code automatically
- determines the Python version and the interpreter.
- Both of these pip spokes contain requirements files that includes websocket
- and its dependencies.
-
- Two different repositories are created for the two spokes:
-
- - @@rules_python~override~pip~pip_39
- - @@rules_python~override~pip~pip_310
-
- The different spoke names are a combination of the hub_name and the Python version.
- In the future we may remove this repository, but we do not support entry points.
- yet, and that functionality exists in these repos.
-
- We also need repositories for the wheels that the different pip spokes contain.
- For each Python version a different wheel repository is created. In our example
- each pip spoke had a requirments file that contained websockets. We
- then create two different wheel repositories that are named the following.
-
- - @@rules_python~override~pip~pip_39_websockets
- - @@rules_python~override~pip~pip_310_websockets
-
- And if the wheel has any other dependies subsequest wheels are created in the same fashion.
-
- We also create a repository for the wheel alias. We want to just use the syntax
- 'requirement("websockets")' we need to have an alias repository that is named:
-
- - @@rules_python~override~pip~pip_websockets
-
- This repository contains alias statements for the different wheel components (pkg, data, etc).
- Each of those aliases has a select that resolves to a spoke repository depending on
- the Python version.
-
- Also we may have more than one hub as defined in a MODULES.bazel file. So we could have multiple
- hubs pointing to various different pip spokes.
-
- Some other business rules notes. A hub can only have one spoke per Python version. We cannot
- have a hub named "pip" that has two spokes that use the Python 3.9 interpreter. Second
- we cannot have the same hub name used in submodules. The hub name has to be globally
- unique.
-
- This implementation reuses elements of non-bzlmod code and also reuses the first implementation
- of pip bzlmod, but adds the capability to have multiple pip.parse calls.
-
- This implementation also handles the creation of whl_modification JSON files that are used
- during the creation of wheel libraries. These JSON files used via the annotations argument
- when calling wheel_installer.py.
-
- Args:
- module_ctx: module contents
-
- """
-
- # Build all of the wheel modifications if the tag class is called.
- _whl_mods_impl(module_ctx)
-
- # Used to track all the different pip hubs and the spoke pip Python
- # versions.
- pip_hub_map = {}
-
- # Keeps track of all the hub's whl repos across the different versions.
- # dict[hub, dict[whl, dict[version, str pip]]]
- # Where hub, whl, and pip are the repo names
- hub_whl_map = {}
-
- for mod in module_ctx.modules:
- for pip_attr in mod.tags.parse:
- hub_name = pip_attr.hub_name
- if hub_name in pip_hub_map:
- # We cannot have two hubs with the same name in different
- # modules.
- if pip_hub_map[hub_name].module_name != mod.name:
- fail((
- "Duplicate cross-module pip hub named '{hub}': pip hub " +
- "names must be unique across modules. First defined " +
- "by module '{first_module}', second attempted by " +
- "module '{second_module}'"
- ).format(
- hub = hub_name,
- first_module = pip_hub_map[hub_name].module_name,
- second_module = mod.name,
- ))
-
- if pip_attr.python_version in pip_hub_map[hub_name].python_versions:
- fail((
- "Duplicate pip python version '{version}' for hub " +
- "'{hub}' in module '{module}': the Python versions " +
- "used for a hub must be unique"
- ).format(
- hub = hub_name,
- module = mod.name,
- version = pip_attr.python_version,
- ))
- else:
- pip_hub_map[pip_attr.hub_name].python_versions.append(pip_attr.python_version)
- else:
- pip_hub_map[pip_attr.hub_name] = struct(
- module_name = mod.name,
- python_versions = [pip_attr.python_version],
- )
-
- _create_versioned_pip_and_whl_repos(module_ctx, pip_attr, hub_whl_map)
-
- for hub_name, whl_map in hub_whl_map.items():
- for whl_name, version_map in whl_map.items():
- if DEFAULT_PYTHON_VERSION not in version_map:
- fail((
- "Default python version '{version}' missing in pip " +
- "hub '{hub}': update your pip.parse() calls so that " +
- 'includes `python_version = "{version}"`'
- ).format(
- version = DEFAULT_PYTHON_VERSION,
- hub = hub_name,
- ))
-
- # Create the alias repositories which contains different select
- # statements These select statements point to the different pip
- # whls that are based on a specific version of Python.
- whl_library_alias(
- name = hub_name + "_" + whl_name,
- wheel_name = whl_name,
- default_version = DEFAULT_PYTHON_VERSION,
- version_map = version_map,
- )
-
- # Create the hub repository for pip.
- pip_hub_repository_bzlmod(
- name = hub_name,
- repo_name = hub_name,
- whl_library_alias_names = whl_map.keys(),
- )
-
-def _pip_parse_ext_attrs():
- attrs = dict({
- "hub_name": attr.string(
- mandatory = True,
- doc = """
-The name of the repo pip dependencies will be accessible from.
-
-This name must be unique between modules; unless your module is guaranteed to
-always be the root module, it's highly recommended to include your module name
-in the hub name. Repo mapping, `use_repo(..., pip="my_modules_pip_deps")`, can
-be used for shorter local names within your module.
-
-Within a module, the same `hub_name` can be specified to group different Python
-versions of pip dependencies under one repository name. This allows using a
-Python version-agnostic name when referring to pip dependencies; the
-correct version will be automatically selected.
-
-Typically, a module will only have a single hub of pip dependencies, but this
-is not required. Each hub is a separate resolution of pip dependencies. This
-means if different programs need different versions of some library, separate
-hubs can be created, and each program can use its respective hub's targets.
-Targets from different hubs should not be used together.
-""",
- ),
- "python_version": attr.string(
- default = DEFAULT_PYTHON_VERSION,
- doc = """
-The Python version to use for resolving the pip dependencies. If not specified,
-then the default Python version (as set by the root module or rules_python)
-will be used.
-
-The version specified here must have a corresponding `python.toolchain()`
-configured. This attribute defaults to the version of the toolchain
-that is set as the default Python version. Or if only one toolchain
-is used, this attribute defaults to that version of Python.
-""",
- ),
- "whl_modifications": attr.label_keyed_string_dict(
- mandatory = False,
- doc = """\
-A dict of labels to wheel names that is typically generated by the whl_modifications.
-The labels are JSON config files describing the modifications.
-""",
- ),
- }, **pip_repository_attrs)
-
- # Like the pip_repository rule, we end up setting this manually so
- # don't allow users to override it.
- attrs.pop("repo_prefix")
-
- # incompatible_generate_aliases is always True in bzlmod
- attrs.pop("incompatible_generate_aliases")
-
- return attrs
-
-def _whl_mod_attrs():
- attrs = {
- "additive_build_content": attr.string(
- doc = "(str, optional): Raw text to add to the generated `BUILD` file of a package.",
- ),
- "additive_build_content_file": attr.label(
- doc = """\
-(label, optional): path to a BUILD file to add to the generated
-`BUILD` file of a package. You cannot use both additive_build_content and additive_build_content_file
-arguments at the same time.""",
- ),
- "copy_executables": attr.string_dict(
- doc = """\
-(dict, optional): A mapping of `src` and `out` files for
-[@bazel_skylib//rules:copy_file.bzl][cf]. Targets generated here will also be flagged as
-executable.""",
- ),
- "copy_files": attr.string_dict(
- doc = """\
-(dict, optional): A mapping of `src` and `out` files for
-[@bazel_skylib//rules:copy_file.bzl][cf]""",
- ),
- "data": attr.string_list(
- doc = """\
-(list, optional): A list of labels to add as `data` dependencies to
-the generated `py_library` target.""",
- ),
- "data_exclude_glob": attr.string_list(
- doc = """\
-(list, optional): A list of exclude glob patterns to add as `data` to
-the generated `py_library` target.""",
- ),
- "hub_name": attr.string(
- doc = """\
-Name of the whl modification, hub we use this name to set the modifications for
-pip.parse. If you have different pip hubs you can use a different name,
-otherwise it is best practice to just use one.
-
-You cannot have the same `hub_name` in different modules. You can reuse the same
-name in the same module for different wheels that you put in the same hub, but you
-cannot have a child module that uses the same `hub_name`.
-""",
- mandatory = True,
- ),
- "srcs_exclude_glob": attr.string_list(
- doc = """\
-(list, optional): A list of labels to add as `srcs` to the generated
-`py_library` target.""",
- ),
- "whl_name": attr.string(
- doc = "The whl name that the modifications are used for.",
- mandatory = True,
- ),
- }
- return attrs
-
-pip = module_extension(
- doc = """\
-This extension is used to make dependencies from pip available.
-
-pip.parse:
-To use, call `pip.parse()` and specify `hub_name` and your requirements file.
-Dependencies will be downloaded and made available in a repo named after the
-`hub_name` argument.
-
-Each `pip.parse()` call configures a particular Python version. Multiple calls
-can be made to configure different Python versions, and will be grouped by
-the `hub_name` argument. This allows the same logical name, e.g. `@pip//numpy`
-to automatically resolve to different, Python version-specific, libraries.
-
-pip.whl_mods:
-This tag class is used to help create JSON files to describe modifications to
-the BUILD files for wheels.
-""",
- implementation = _pip_impl,
- tag_classes = {
- "parse": tag_class(
- attrs = _pip_parse_ext_attrs(),
- doc = """\
-This tag class is used to create a pip hub and all of the spokes that are part of that hub.
-This tag class reuses most of the pip attributes that are found in
-@rules_python//python/pip_install:pip_repository.bzl.
-The exceptions are it does not use the args 'repo_prefix',
-and 'incompatible_generate_aliases'. We set the repository prefix
-for the user and the alias arg is always True in bzlmod.
-""",
- ),
- "whl_mods": tag_class(
- attrs = _whl_mod_attrs(),
- doc = """\
-This tag class is used to create JSON file that are used when calling wheel_builder.py. These
-JSON files contain instructions on how to modify a wheel's project. Each of the attributes
-create different modifications based on the type of attribute. Previously to bzlmod these
-JSON files where referred to as annotations, and were renamed to whl_modifications in this
-extension.
-""",
- ),
- },
-)
-
-def _whl_mods_repo_impl(rctx):
- rctx.file("BUILD.bazel", "")
- for whl_name, mods in rctx.attr.whl_mods.items():
- rctx.file("{}.json".format(whl_name), mods)
-
-_whl_mods_repo = repository_rule(
- doc = """\
-This rule creates json files based on the whl_mods attribute.
-""",
- implementation = _whl_mods_repo_impl,
- attrs = {
- "whl_mods": attr.string_dict(
- mandatory = True,
- doc = "JSON endcoded string that is provided to wheel_builder.py",
- ),
- },
-)
+pip = _pip
diff --git a/python/extensions/python.bzl b/python/extensions/python.bzl
index 2d4032a..5428b75 100644
--- a/python/extensions/python.bzl
+++ b/python/extensions/python.bzl
@@ -14,245 +14,6 @@
"Python toolchain module extensions for use with bzlmod"
-load("//python:repositories.bzl", "python_register_toolchains")
-load("//python/extensions/private:pythons_hub.bzl", "hub_repo")
-load("//python/private:toolchains_repo.bzl", "multi_toolchain_aliases")
+load("//python/private/bzlmod:python.bzl", _python = "python")
-# This limit can be increased essentially arbitrarily, but doing so will cause a rebuild of all
-# targets using any of these toolchains due to the changed repository name.
-_MAX_NUM_TOOLCHAINS = 9999
-_TOOLCHAIN_INDEX_PAD_LENGTH = len(str(_MAX_NUM_TOOLCHAINS))
-
-def _toolchain_prefix(index, name):
- """Prefixes the given name with the index, padded with zeros to ensure lexicographic sorting.
-
- Examples:
- _toolchain_prefix( 2, "foo") == "_0002_foo_"
- _toolchain_prefix(2000, "foo") == "_2000_foo_"
- """
- return "_{}_{}_".format(_left_pad_zero(index, _TOOLCHAIN_INDEX_PAD_LENGTH), name)
-
-def _left_pad_zero(index, length):
- if index < 0:
- fail("index must be non-negative")
- return ("0" * length + str(index))[-length:]
-
-# Printing a warning msg not debugging, so we have to disable
-# the buildifier check.
-# buildifier: disable=print
-def _print_warn(msg):
- print("WARNING:", msg)
-
-def _python_register_toolchains(name, toolchain_attr, version_constraint):
- """Calls python_register_toolchains and returns a struct used to collect the toolchains.
- """
- python_register_toolchains(
- name = name,
- python_version = toolchain_attr.python_version,
- register_coverage_tool = toolchain_attr.configure_coverage_tool,
- ignore_root_user_error = toolchain_attr.ignore_root_user_error,
- set_python_version_constraint = version_constraint,
- )
- return struct(
- python_version = toolchain_attr.python_version,
- set_python_version_constraint = str(version_constraint),
- name = name,
- )
-
-def _python_impl(module_ctx):
- # The toolchain info structs to register, in the order to register them in.
- toolchains = []
-
- # We store the default toolchain separately to ensure it is the last
- # toolchain added to toolchains.
- default_toolchain = None
-
- # Map of string Major.Minor to the toolchain name and module name
- global_toolchain_versions = {}
-
- for mod in module_ctx.modules:
- module_toolchain_versions = []
-
- for toolchain_attr in mod.tags.toolchain:
- toolchain_version = toolchain_attr.python_version
- toolchain_name = "python_" + toolchain_version.replace(".", "_")
-
- # Duplicate versions within a module indicate a misconfigured module.
- if toolchain_version in module_toolchain_versions:
- _fail_duplicate_module_toolchain_version(toolchain_version, mod.name)
- module_toolchain_versions.append(toolchain_version)
-
- # Ignore version collisions in the global scope because there isn't
- # much else that can be done. Modules don't know and can't control
- # what other modules do, so the first in the dependency graph wins.
- if toolchain_version in global_toolchain_versions:
- _warn_duplicate_global_toolchain_version(
- toolchain_version,
- first = global_toolchain_versions[toolchain_version],
- second_toolchain_name = toolchain_name,
- second_module_name = mod.name,
- )
- continue
- global_toolchain_versions[toolchain_version] = struct(
- toolchain_name = toolchain_name,
- module_name = mod.name,
- )
-
- # Only the root module and rules_python are allowed to specify the default
- # toolchain for a couple reasons:
- # * It prevents submodules from specifying different defaults and only
- # one of them winning.
- # * rules_python needs to set a soft default in case the root module doesn't,
- # e.g. if the root module doesn't use Python itself.
- # * The root module is allowed to override the rules_python default.
- if mod.is_root:
- # A single toolchain is treated as the default because it's unambiguous.
- is_default = toolchain_attr.is_default or len(mod.tags.toolchain) == 1
- elif mod.name == "rules_python" and not default_toolchain:
- # We don't do the len() check because we want the default that rules_python
- # sets to be clearly visible.
- is_default = toolchain_attr.is_default
- else:
- is_default = False
-
- # We have already found one default toolchain, and we can only have
- # one.
- if is_default and default_toolchain != None:
- _fail_multiple_default_toolchains(
- first = default_toolchain.name,
- second = toolchain_name,
- )
-
- toolchain_info = _python_register_toolchains(
- toolchain_name,
- toolchain_attr,
- version_constraint = not is_default,
- )
-
- if is_default:
- default_toolchain = toolchain_info
- else:
- toolchains.append(toolchain_info)
-
- # A default toolchain is required so that the non-version-specific rules
- # are able to match a toolchain.
- if default_toolchain == None:
- fail("No default Python toolchain configured. Is rules_python missing `is_default=True`?")
-
- # The last toolchain in the BUILD file is set as the default
- # toolchain. We need the default last.
- toolchains.append(default_toolchain)
-
- if len(toolchains) > _MAX_NUM_TOOLCHAINS:
- fail("more than {} python versions are not supported".format(_MAX_NUM_TOOLCHAINS))
-
- # Create the pythons_hub repo for the interpreter meta data and the
- # the various toolchains.
- hub_repo(
- name = "pythons_hub",
- default_python_version = default_toolchain.python_version,
- toolchain_prefixes = [
- _toolchain_prefix(index, toolchain.name)
- for index, toolchain in enumerate(toolchains)
- ],
- toolchain_python_versions = [t.python_version for t in toolchains],
- toolchain_set_python_version_constraints = [t.set_python_version_constraint for t in toolchains],
- toolchain_user_repository_names = [t.name for t in toolchains],
- )
-
- # This is require in order to support multiple version py_test
- # and py_binary
- multi_toolchain_aliases(
- name = "python_versions",
- python_versions = {
- version: entry.toolchain_name
- for version, entry in global_toolchain_versions.items()
- },
- )
-
-def _fail_duplicate_module_toolchain_version(version, module):
- fail(("Duplicate module toolchain version: module '{module}' attempted " +
- "to use version '{version}' multiple times in itself").format(
- version = version,
- module = module,
- ))
-
-def _warn_duplicate_global_toolchain_version(version, first, second_toolchain_name, second_module_name):
- _print_warn((
- "Ignoring toolchain '{second_toolchain}' from module '{second_module}': " +
- "Toolchain '{first_toolchain}' from module '{first_module}' " +
- "already registered Python version {version} and has precedence"
- ).format(
- first_toolchain = first.toolchain_name,
- first_module = first.module_name,
- second_module = second_module_name,
- second_toolchain = second_toolchain_name,
- version = version,
- ))
-
-def _fail_multiple_default_toolchains(first, second):
- fail(("Multiple default toolchains: only one toolchain " +
- "can have is_default=True. First default " +
- "was toolchain '{first}'. Second was '{second}'").format(
- first = first,
- second = second,
- ))
-
-python = module_extension(
- doc = """Bzlmod extension that is used to register Python toolchains.
-""",
- implementation = _python_impl,
- tag_classes = {
- "toolchain": tag_class(
- doc = """Tag class used to register Python toolchains.
-Use this tag class to register one or more Python toolchains. This class
-is also potentially called by sub modules. The following covers different
-business rules and use cases.
-
-Toolchains in the Root Module
-
-This class registers all toolchains in the root module.
-
-Toolchains in Sub Modules
-
-It will create a toolchain that is in a sub module, if the toolchain
-of the same name does not exist in the root module. The extension stops name
-clashing between toolchains in the root module and toolchains in sub modules.
-You cannot configure more than one toolchain as the default toolchain.
-
-Toolchain set as the default version
-
-This extension will not create a toolchain that exists in a sub module,
-if the sub module toolchain is marked as the default version. If you have
-more than one toolchain in your root module, you need to set one of the
-toolchains as the default version. If there is only one toolchain it
-is set as the default toolchain.
-
-Toolchain repository name
-
-A toolchain's repository name uses the format `python_{major}_{minor}`, e.g.
-`python_3_10`. The `major` and `minor` components are
-`major` and `minor` are the Python version from the `python_version` attribute.
-""",
- 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,
- ),
- "is_default": attr.bool(
- mandatory = False,
- doc = "Whether the toolchain is the default version",
- ),
- "python_version": attr.string(
- mandatory = True,
- doc = "The Python version, in `major.minor` format, e.g '3.12', to create a toolchain for.",
- ),
- },
- ),
- },
-)
+python = _python
diff --git a/python/packaging.bzl b/python/packaging.bzl
index d9b9d02..f811965 100644
--- a/python/packaging.bzl
+++ b/python/packaging.bzl
@@ -14,6 +14,7 @@
"""Public API for for building wheels."""
+load("//python:py_binary.bzl", "py_binary")
load("//python/private:py_package.bzl", "py_package_lib")
load("//python/private:py_wheel.bzl", _PyWheelInfo = "PyWheelInfo", _py_wheel = "py_wheel")
load("//python/private:util.bzl", "copy_propagating_kwargs")
@@ -65,7 +66,7 @@ This also has the advantage that stamping information is included in the wheel's
implementation = _py_wheel_dist_impl,
attrs = {
"out": attr.string(doc = "name of the resulting directory", mandatory = True),
- "wheel": attr.label(doc = "a [py_wheel rule](/docs/packaging.md#py_wheel_rule)", providers = [PyWheelInfo]),
+ "wheel": attr.label(doc = "a [py_wheel target](#py_wheel)", providers = [PyWheelInfo]),
},
)
@@ -114,9 +115,9 @@ def py_wheel(name, twine = None, publish_args = [], **kwargs):
)
```
- To publish the wheel to Pypi, the twine package is required.
- rules_python doesn't provide twine itself, see https://github.com/bazelbuild/rules_python/issues/1016
- However you can install it with pip_parse, just like we do in the WORKSPACE file in rules_python.
+ To publish the wheel to PyPI, the twine package is required.
+ rules_python doesn't provide twine itself, see [https://github.com/bazelbuild/rules_python/issues/1016].
+ However you can install it with [pip_parse](#pip_parse), just like we do in the WORKSPACE file in rules_python.
Once you've installed twine, you can pass its label to the `twine` attribute of this macro,
to get a "[name].publish" target.
@@ -167,7 +168,7 @@ def py_wheel(name, twine = None, publish_args = [], **kwargs):
# TODO: use py_binary from //python:defs.bzl after our stardoc setup is less brittle
# buildifier: disable=native-py
- native.py_binary(
+ py_binary(
name = "{}.publish".format(name),
srcs = [twine_main],
args = twine_args,
diff --git a/python/pip.bzl b/python/pip.bzl
index cae1591..aeedf57 100644
--- a/python/pip.bzl
+++ b/python/pip.bzl
@@ -11,153 +11,24 @@
# 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 pip requirements into Bazel."""
+"""Rules for pip integration.
+
+This contains a set of rules that are used to support inclusion of third-party
+dependencies via fully locked `requirements.txt` files. Some of the exported
+symbols should not be used and they are either undocumented here or marked as
+for internal use only.
+"""
load("//python/pip_install:pip_repository.bzl", "pip_repository", _package_annotation = "package_annotation")
-load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
load("//python/pip_install:requirements.bzl", _compile_pip_requirements = "compile_pip_requirements")
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
-load(":versions.bzl", "MINOR_MAPPING")
+load("//python/private:full_version.bzl", "full_version")
+load("//python/private:normalize_name.bzl", "normalize_name")
+load("//python/private:render_pkg_aliases.bzl", "NO_MATCH_ERROR_MESSAGE_TEMPLATE")
compile_pip_requirements = _compile_pip_requirements
package_annotation = _package_annotation
-
-def pip_install(requirements = None, name = "pip", **kwargs):
- """Accepts a locked/compiled requirements file and installs the dependencies listed within.
-
- ```python
- load("@rules_python//python:pip.bzl", "pip_install")
-
- pip_install(
- name = "pip_deps",
- requirements = ":requirements.txt",
- )
-
- load("@pip_deps//:requirements.bzl", "install_deps")
-
- install_deps()
- ```
-
- Args:
- requirements (Label): A 'requirements.txt' pip requirements file.
- name (str, optional): A unique name for the created external repository (default 'pip').
- **kwargs (dict): Additional arguments to the [`pip_repository`](./pip_repository.md) repository rule.
- """
-
- # buildifier: disable=print
- print("pip_install is deprecated. Please switch to pip_parse. pip_install will be removed in a future release.")
- pip_parse(requirements = requirements, name = name, **kwargs)
-
-def pip_parse(requirements = None, requirements_lock = None, name = "pip_parsed_deps", **kwargs):
- """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, see the "vendoring" section below.
-
- This macro wraps the [`pip_repository`](./pip_repository.md) rule that invokes `pip`.
- In your WORKSPACE file:
-
- ```python
- load("@rules_python//python:pip.bzl", "pip_parse")
-
- pip_parse(
- name = "pip_deps",
- requirements_lock = ":requirements.txt",
- )
-
- load("@pip_deps//:requirements.bzl", "install_deps")
-
- install_deps()
- ```
-
- You can then reference installed dependencies from a `BUILD` file with:
-
- ```python
- load("@pip_deps//:requirements.bzl", "requirement")
-
- py_library(
- name = "bar",
- ...
- deps = [
- "//my/other:dep",
- requirement("requests"),
- requirement("numpy"),
- ],
- )
- ```
-
- In addition to the `requirement` macro, which is used to access the generated `py_library`
- target generated from a package's wheel, The generated `requirements.bzl` file contains
- functionality for exposing [entry points][whl_ep] as `py_binary` targets as well.
-
- [whl_ep]: https://packaging.python.org/specifications/entry-points/
-
- ```python
- load("@pip_deps//:requirements.bzl", "entry_point")
-
- alias(
- name = "pip-compile",
- actual = entry_point(
- pkg = "pip-tools",
- script = "pip-compile",
- ),
- )
- ```
-
- Note that for packages whose name and script are the same, only the name of the package
- is needed when calling the `entry_point` macro.
-
- ```python
- load("@pip_deps//:requirements.bzl", "entry_point")
-
- alias(
- name = "flake8",
- actual = entry_point("flake8"),
- )
- ```
-
- ## Vendoring the requirements.bzl file
-
- In some cases you may not want to generate the requirements.bzl file as a repository rule
- while Bazel is fetching dependencies. For example, if you produce a reusable Bazel module
- such as a ruleset, you may want to include the requirements.bzl file rather than make your users
- install the WORKSPACE setup to generate it.
- See https://github.com/bazelbuild/rules_python/issues/608
-
- This is the same workflow as Gazelle, which creates `go_repository` rules with
- [`update-repos`](https://github.com/bazelbuild/bazel-gazelle#update-repos)
-
- To do this, use the "write to source file" pattern documented in
- https://blog.aspect.dev/bazel-can-write-to-the-source-folder
- to put a copy of the generated requirements.bzl into your project.
- Then load the requirements.bzl file directly rather than from the generated repository.
- See the example in rules_python/examples/pip_parse_vendored.
-
- Args:
- requirements_lock (Label): 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'.
- Note that if your lockfile is platform-dependent, you can use the `requirements_[platform]`
- attributes.
- requirements (Label): Deprecated. See requirements_lock.
- name (str, optional): The name of the generated repository. The generated repositories
- containing each requirement will be of the form `<name>_<requirement-name>`.
- **kwargs (dict): Additional arguments to the [`pip_repository`](./pip_repository.md) repository rule.
- """
- pip_install_dependencies()
-
- # Temporary compatibility shim.
- # pip_install was previously document to use requirements while pip_parse was using requirements_lock.
- # We would prefer everyone move to using requirements_lock, but we maintain a temporary shim.
- reqs_to_use = requirements_lock if requirements_lock else requirements
-
- pip_repository(
- name = name,
- requirements_lock = reqs_to_use,
- **kwargs
- )
+pip_parse = pip_repository
def _multi_pip_parse_impl(rctx):
rules_python = rctx.attr._rules_python_workspace.workspace_name
@@ -192,18 +63,28 @@ _process_requirements(
)
install_deps_calls.append(install_deps_call)
+ # NOTE @aignas 2023-10-31: I am not sure it is possible to render aliases
+ # for all of the packages using the `render_pkg_aliases` function because
+ # we need to know what the list of packages for each version is and then
+ # we would be creating directories for each.
+ macro_tmpl = "@%s_{}//:{}" % rctx.attr.name
+
requirements_bzl = """\
# Generated by python/pip.bzl
-load("@{rules_python}//python:pip.bzl", "whl_library_alias")
+load("@{rules_python}//python:pip.bzl", "whl_library_alias", "pip_utils")
{load_statements}
_wheel_names = []
_version_map = dict()
def _process_requirements(pkg_labels, python_version, repo_prefix):
for pkg_label in pkg_labels:
- workspace_name = Label(pkg_label).workspace_name
- wheel_name = workspace_name[len(repo_prefix):]
+ wheel_name = Label(pkg_label).package
+ if not wheel_name:
+ # We are dealing with the cases where we don't have aliases.
+ workspace_name = Label(pkg_label).workspace_name
+ wheel_name = workspace_name[len(repo_prefix):]
+
_wheel_names.append(wheel_name)
if not wheel_name in _version_map:
_version_map[wheel_name] = dict()
@@ -211,20 +92,17 @@ def _process_requirements(pkg_labels, python_version, repo_prefix):
{process_requirements_calls}
-def _clean_name(name):
- return name.replace("-", "_").replace(".", "_").lower()
-
def requirement(name):
- return "@{name}_" + _clean_name(name) + "//:pkg"
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "pkg")
def whl_requirement(name):
- return "@{name}_" + _clean_name(name) + "//:whl"
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "whl")
def data_requirement(name):
- return "@{name}_" + _clean_name(name) + "//:data"
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "data")
def dist_info_requirement(name):
- return "@{name}_" + _clean_name(name) + "//:dist_info"
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "dist_info")
def entry_point(pkg, script = None):
fail("Not implemented yet")
@@ -242,6 +120,7 @@ def install_deps(**whl_library_kwargs):
name = rctx.attr.name,
install_deps_calls = "\n".join(install_deps_calls),
load_statements = "\n".join(load_statements),
+ macro_tmpl = macro_tmpl,
process_requirements_calls = "\n".join(process_requirements_calls),
rules_python = rules_python,
default_version = rctx.attr.default_version,
@@ -260,13 +139,10 @@ _multi_pip_parse = repository_rule(
def _whl_library_alias_impl(rctx):
rules_python = rctx.attr._rules_python_workspace.workspace_name
- if rctx.attr.default_version not in rctx.attr.version_map:
- fail(
- """
-Unable to find '{}' in your version map, you may need to update your requirement files.
- """.format(rctx.attr.version_map),
- )
- default_repo_prefix = rctx.attr.version_map[rctx.attr.default_version]
+ if rctx.attr.default_version:
+ default_repo_prefix = rctx.attr.version_map[rctx.attr.default_version]
+ else:
+ default_repo_prefix = None
version_map = rctx.attr.version_map.items()
build_content = ["# Generated by python/pip.bzl"]
for alias_name in ["pkg", "whl", "data", "dist_info"]:
@@ -289,6 +165,7 @@ def _whl_library_render_alias_target(
# is canonical, so we have to add a second @.
if BZLMOD_ENABLED:
rules_python = "@" + rules_python
+
alias = ["""\
alias(
name = "{alias_name}",
@@ -296,7 +173,7 @@ alias(
for [python_version, repo_prefix] in version_map:
alias.append("""\
"@{rules_python}//python/config_settings:is_python_{full_python_version}": "{actual}",""".format(
- full_python_version = MINOR_MAPPING[python_version] if python_version in MINOR_MAPPING else python_version,
+ full_python_version = full_version(python_version),
actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
repo_prefix = repo_prefix,
wheel_name = wheel_name,
@@ -304,23 +181,42 @@ alias(
),
rules_python = rules_python,
))
- alias.append("""\
- "//conditions:default": "{default_actual}",
- }}),
- visibility = ["//visibility:public"],
-)""".format(
+ if default_repo_prefix:
default_actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
repo_prefix = default_repo_prefix,
wheel_name = wheel_name,
alias_name = alias_name,
- ),
- ))
+ )
+ alias.append(' "//conditions:default": "{default_actual}",'.format(
+ default_actual = default_actual,
+ ))
+
+ alias.append(" },") # Close select expression condition dict
+ if not default_repo_prefix:
+ supported_versions = sorted([python_version for python_version, _ in version_map])
+ alias.append(' no_match_error="""{}""",'.format(
+ NO_MATCH_ERROR_MESSAGE_TEMPLATE.format(
+ supported_versions = ", ".join(supported_versions),
+ rules_python = rules_python,
+ ),
+ ))
+ alias.append(" ),") # Close the select expression
+ alias.append(' visibility = ["//visibility:public"],')
+ alias.append(")") # Close the alias() expression
return "\n".join(alias)
whl_library_alias = repository_rule(
_whl_library_alias_impl,
attrs = {
- "default_version": attr.string(mandatory = True),
+ "default_version": attr.string(
+ mandatory = False,
+ doc = "Optional Python version in major.minor format, e.g. '3.10'." +
+ "The Python version of the wheel to use when the versions " +
+ "from `version_map` don't match. This allows the default " +
+ "(version unaware) rules to match and select a wheel. If " +
+ "not specified, then the default rules won't be able to " +
+ "resolve a wheel and an error will occur.",
+ ),
"version_map": attr.string_dict(mandatory = True),
"wheel_name": attr.string(mandatory = True),
"_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),
@@ -365,3 +261,8 @@ def multi_pip_parse(name, default_version, python_versions, python_interpreter_t
default_version = default_version,
pip_parses = pip_parses,
)
+
+# Extra utilities visible to rules_python users.
+pip_utils = struct(
+ normalize_name = normalize_name,
+)
diff --git a/python/pip_install/BUILD.bazel b/python/pip_install/BUILD.bazel
index e8e8633..4bcd5b8 100644
--- a/python/pip_install/BUILD.bazel
+++ b/python/pip_install/BUILD.bazel
@@ -1,16 +1,95 @@
+# 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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+package(
+ default_visibility = ["//:__subpackages__"],
+)
+
+bzl_library(
+ name = "pip_repository_bzl",
+ srcs = ["pip_repository.bzl"],
+ deps = [
+ ":repositories_bzl",
+ ":requirements_parser_bzl",
+ "//python:repositories_bzl",
+ "//python:versions_bzl",
+ "//python/pip_install/private:generate_group_library_build_bazel_bzl",
+ "//python/pip_install/private:generate_whl_library_build_bazel_bzl",
+ "//python/pip_install/private:srcs_bzl",
+ "//python/private:bzlmod_enabled_bzl",
+ "//python/private:normalize_name_bzl",
+ "//python/private:parse_whl_name_bzl",
+ "//python/private:patch_whl_bzl",
+ "//python/private:render_pkg_aliases_bzl",
+ "//python/private:toolchains_repo_bzl",
+ "//python/private:which_bzl",
+ "//python/private:whl_target_platforms_bzl",
+ "@bazel_skylib//lib:sets",
+ ],
+)
+
+bzl_library(
+ name = "requirements_bzl",
+ srcs = ["requirements.bzl"],
+ deps = [
+ ":repositories_bzl",
+ "//python:defs_bzl",
+ ],
+)
+
+bzl_library(
+ name = "requirements_parser_bzl",
+ srcs = ["requirements_parser.bzl"],
+)
+
+bzl_library(
+ name = "repositories_bzl",
+ srcs = ["repositories.bzl"],
+ deps = [
+ "//:version_bzl",
+ "//python/private:bazel_tools_bzl",
+ "@bazel_skylib//lib:versions",
+ ],
+)
+
filegroup(
name = "distribution",
srcs = glob(["*.bzl"]) + [
"BUILD.bazel",
+ "pip_repository_requirements.bzl.tmpl",
"//python/pip_install/private:distribution",
"//python/pip_install/tools/dependency_resolver:distribution",
- "//python/pip_install/tools/lib:distribution",
"//python/pip_install/tools/wheel_installer:distribution",
],
visibility = ["//:__pkg__"],
)
filegroup(
+ name = "repositories",
+ srcs = ["repositories.bzl"],
+ visibility = ["//tools/private/update_deps:__pkg__"],
+)
+
+filegroup(
+ name = "requirements_txt",
+ srcs = ["tools/requirements.txt"],
+ visibility = ["//tools/private/update_deps:__pkg__"],
+)
+
+filegroup(
name = "bzl",
srcs = glob(["*.bzl"]) + [
"//python/pip_install/private:bzl_srcs",
@@ -22,8 +101,9 @@ filegroup(
name = "py_srcs",
srcs = [
"//python/pip_install/tools/dependency_resolver:py_srcs",
- "//python/pip_install/tools/lib:py_srcs",
"//python/pip_install/tools/wheel_installer:py_srcs",
+ "//python/private:repack_whl.py",
+ "//tools:wheelmaker.py",
],
visibility = ["//python/pip_install/private:__pkg__"],
)
diff --git a/python/pip_install/pip_hub_repository_requirements_bzlmod.bzl.tmpl b/python/pip_install/pip_hub_repository_requirements_bzlmod.bzl.tmpl
deleted file mode 100644
index 4a3d512..0000000
--- a/python/pip_install/pip_hub_repository_requirements_bzlmod.bzl.tmpl
+++ /dev/null
@@ -1,35 +0,0 @@
-"""Starlark representation of locked requirements.
-
-@generated by rules_python pip_parse repository rule
-from %%REQUIREMENTS_LOCK%%.
-
-This file is different from the other bzlmod template
-because we do not support entry_point yet.
-"""
-
-all_requirements = %%ALL_REQUIREMENTS%%
-
-all_whl_requirements = %%ALL_WHL_REQUIREMENTS%%
-
-all_data_requirements = %%ALL_DATA_REQUIREMENTS%%
-
-def _clean_name(name):
- return name.replace("-", "_").replace(".", "_").lower()
-
-def requirement(name):
- return "%%MACRO_TMPL%%".format(_clean_name(name), "pkg")
-
-def whl_requirement(name):
- return "%%MACRO_TMPL%%".format(_clean_name(name), "whl")
-
-def data_requirement(name):
- return "%%MACRO_TMPL%%".format(_clean_name(name), "data")
-
-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.
- """
- # TODO: https://github.com/bazelbuild/rules_python/issues/1262
- print("not implemented")
diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl
index 99d1fb0..3e4878b 100644
--- a/python/pip_install/pip_repository.bzl
+++ b/python/pip_install/pip_repository.bzl
@@ -14,19 +14,29 @@
""
-load("//python:repositories.bzl", "get_interpreter_dirname", "is_standalone_interpreter")
+load("@bazel_skylib//lib:sets.bzl", "sets")
+load("//python:repositories.bzl", "is_standalone_interpreter")
load("//python:versions.bzl", "WINDOWS_NAME")
load("//python/pip_install:repositories.bzl", "all_requirements")
load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
+load("//python/pip_install/private:generate_group_library_build_bazel.bzl", "generate_group_library_build_bazel")
+load("//python/pip_install/private:generate_whl_library_build_bazel.bzl", "generate_whl_library_build_bazel")
load("//python/pip_install/private:srcs.bzl", "PIP_INSTALL_PY_SRCS")
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
load("//python/private:normalize_name.bzl", "normalize_name")
+load("//python/private:parse_whl_name.bzl", "parse_whl_name")
+load("//python/private:patch_whl.bzl", "patch_whl")
+load("//python/private:render_pkg_aliases.bzl", "render_pkg_aliases")
load("//python/private:toolchains_repo.bzl", "get_host_os_arch")
+load("//python/private:which.bzl", "which_with_fail")
+load("//python/private:whl_target_platforms.bzl", "whl_target_platforms")
CPPFLAGS = "CPPFLAGS"
COMMAND_LINE_TOOLS_PATH_SLUG = "commandlinetools"
+_WHEEL_ENTRY_POINT_PREFIX = "rules_python_wheel_entry_point"
+
def _construct_pypath(rctx):
"""Helper function to construct a PYTHONPATH.
@@ -35,18 +45,15 @@ def _construct_pypath(rctx):
Args:
rctx: Handle to the repository_context.
+
Returns: String of the PYTHONPATH.
"""
- # Get the root directory of these rules
- rules_root = rctx.path(Label("//:BUILD.bazel")).dirname
- thirdparty_roots = [
- # Includes all the external dependencies from repositories.bzl
- rctx.path(Label("@" + repo + "//:BUILD.bazel")).dirname
- for repo in all_requirements
- ]
separator = ":" if not "windows" in rctx.os.name.lower() else ";"
- pypath = separator.join([str(p) for p in [rules_root] + thirdparty_roots])
+ pypath = separator.join([
+ str(rctx.path(entry).dirname)
+ for entry in rctx.attr._python_path_entries
+ ])
return pypath
def _get_python_interpreter_attr(rctx):
@@ -71,7 +78,9 @@ def _resolve_python_interpreter(rctx):
Args:
rctx: Handle to the rule repository context.
- Returns: Python interpreter path.
+
+ Returns:
+ `path` object, for the resolved path to the Python interpreter.
"""
python_interpreter = _get_python_interpreter_attr(rctx)
@@ -86,10 +95,13 @@ def _resolve_python_interpreter(rctx):
if os == WINDOWS_NAME:
python_interpreter = python_interpreter.realpath
elif "/" not in python_interpreter:
+ # It's a plain command, e.g. "python3", to look up in the environment.
found_python_interpreter = rctx.which(python_interpreter)
if not found_python_interpreter:
fail("python interpreter `{}` not found in PATH".format(python_interpreter))
python_interpreter = found_python_interpreter
+ else:
+ python_interpreter = rctx.path(python_interpreter)
return python_interpreter
def _get_xcode_location_cflags(rctx):
@@ -104,10 +116,7 @@ def _get_xcode_location_cflags(rctx):
if not rctx.os.name.lower().startswith("mac os"):
return []
- # Locate xcode-select
- xcode_select = rctx.which("xcode-select")
-
- xcode_sdk_location = rctx.execute([xcode_select, "--print-path"])
+ xcode_sdk_location = rctx.execute([which_with_fail("xcode-select", rctx), "--print-path"])
if xcode_sdk_location.return_code != 0:
return []
@@ -121,7 +130,7 @@ def _get_xcode_location_cflags(rctx):
"-isysroot {}/SDKs/MacOSX.sdk".format(xcode_root),
]
-def _get_toolchain_unix_cflags(rctx):
+def _get_toolchain_unix_cflags(rctx, python_interpreter):
"""Gather cflags from a standalone toolchain for unix systems.
Pip won't be able to compile c extensions from sdists with the pre built python distributions from indygreg
@@ -133,11 +142,11 @@ def _get_toolchain_unix_cflags(rctx):
return []
# Only update the location when using a standalone toolchain.
- if not is_standalone_interpreter(rctx, rctx.attr.python_interpreter_target):
+ if not is_standalone_interpreter(rctx, python_interpreter):
return []
er = rctx.execute([
- rctx.path(rctx.attr.python_interpreter_target).realpath,
+ python_interpreter,
"-c",
"import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}', end='')",
])
@@ -145,7 +154,7 @@ def _get_toolchain_unix_cflags(rctx):
fail("could not get python version from interpreter (status {}): {}".format(er.return_code, er.stderr))
_python_version = er.stdout
include_path = "{}/include/python{}".format(
- get_interpreter_dirname(rctx, rctx.attr.python_interpreter_target),
+ python_interpreter.dirname,
_python_version,
)
@@ -216,11 +225,12 @@ def _parse_optional_attrs(rctx, args):
return args
-def _create_repository_execution_environment(rctx):
+def _create_repository_execution_environment(rctx, python_interpreter):
"""Create a environment dictionary for processes we spawn with rctx.execute.
Args:
- rctx: The repository context.
+ rctx (repository_ctx): The repository context.
+ python_interpreter (path): The resolved python interpreter.
Returns:
Dictionary of environment variable suitable to pass to rctx.execute.
"""
@@ -228,7 +238,7 @@ def _create_repository_execution_environment(rctx):
# Gather any available CPPFLAGS values
cppflags = []
cppflags.extend(_get_xcode_location_cflags(rctx))
- cppflags.extend(_get_toolchain_unix_cflags(rctx))
+ cppflags.extend(_get_toolchain_unix_cflags(rctx, python_interpreter))
env = {
"PYTHONPATH": _construct_pypath(rctx),
@@ -268,163 +278,49 @@ A requirements_lock attribute must be specified, or a platform-specific lockfile
""")
return requirements_txt
-def _pkg_aliases(rctx, repo_name, bzl_packages):
- """Create alias declarations for each python dependency.
-
- The aliases should be appended to the pip_repository BUILD.bazel file. These aliases
- allow users to use requirement() without needed a corresponding `use_repo()` for each dep
- when using bzlmod.
-
- Args:
- rctx: the repository context.
- repo_name: the repository name of the parent that is visible to the users.
- bzl_packages: the list of packages to setup.
- """
- for name in bzl_packages:
- build_content = """package(default_visibility = ["//visibility:public"])
-
-alias(
- name = "{name}",
- actual = "@{repo_name}_{dep}//:pkg",
-)
-
-alias(
- name = "pkg",
- actual = "@{repo_name}_{dep}//:pkg",
-)
-
-alias(
- name = "whl",
- actual = "@{repo_name}_{dep}//:whl",
-)
-
-alias(
- name = "data",
- actual = "@{repo_name}_{dep}//:data",
-)
-
-alias(
- name = "dist_info",
- actual = "@{repo_name}_{dep}//:dist_info",
-)
-""".format(
- name = name,
- repo_name = repo_name,
- dep = name,
- )
- rctx.file("{}/BUILD.bazel".format(name), build_content)
-
-def _create_pip_repository_bzlmod(rctx, bzl_packages, requirements):
- repo_name = rctx.attr.repo_name
- build_contents = _BUILD_FILE_CONTENTS
- _pkg_aliases(rctx, 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.
- macro_tmpl = "@@{name}//{{}}:{{}}".format(name = rctx.attr.name)
-
- rctx.file("BUILD.bazel", build_contents)
- rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
- "%%ALL_DATA_REQUIREMENTS%%": _format_repr_list([
- macro_tmpl.format(p, "data")
- for p in bzl_packages
- ]),
- "%%ALL_REQUIREMENTS%%": _format_repr_list([
- macro_tmpl.format(p, p)
- for p in bzl_packages
- ]),
- "%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
- macro_tmpl.format(p, "whl")
- for p in bzl_packages
- ]),
- "%%MACRO_TMPL%%": macro_tmpl,
- "%%NAME%%": rctx.attr.name,
- "%%REQUIREMENTS_LOCK%%": requirements,
- })
-
-def _pip_hub_repository_bzlmod_impl(rctx):
- bzl_packages = rctx.attr.whl_library_alias_names
- _create_pip_repository_bzlmod(rctx, bzl_packages, "")
-
-pip_hub_repository_bzlmod_attrs = {
- "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.",
- ),
- "whl_library_alias_names": attr.string_list(
- mandatory = True,
- doc = "The list of whl alias that we use to build aliases and the whl names",
- ),
- "_template": attr.label(
- default = ":pip_hub_repository_requirements_bzlmod.bzl.tmpl",
- ),
-}
-
-pip_hub_repository_bzlmod = repository_rule(
- attrs = pip_hub_repository_bzlmod_attrs,
- doc = """A rule for bzlmod mulitple pip repository creation. PRIVATE USE ONLY.""",
- implementation = _pip_hub_repository_bzlmod_impl,
-)
-
-def _pip_repository_bzlmod_impl(rctx):
+def _pip_repository_impl(rctx):
requirements_txt = locked_requirements_label(rctx, rctx.attr)
content = rctx.read(requirements_txt)
parsed_requirements_txt = parse_requirements(content)
packages = [(normalize_name(name), requirement) for name, requirement in parsed_requirements_txt.requirements]
- bzl_packages = sorted([name for name, _ in packages])
- _create_pip_repository_bzlmod(rctx, bzl_packages, str(requirements_txt))
-
-pip_repository_bzlmod_attrs = {
- "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",
- ),
- "requirements_linux": attr.label(
- allow_single_file = True,
- doc = "Override the requirements_lock attribute when the host platform is Linux",
- ),
- "requirements_lock": attr.label(
- allow_single_file = True,
- doc = """
-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'.
-""",
- ),
- "requirements_windows": attr.label(
- allow_single_file = True,
- doc = "Override the requirements_lock attribute when the host platform is Windows",
- ),
- "_template": attr.label(
- default = ":pip_repository_requirements_bzlmod.bzl.tmpl",
- ),
-}
-
-pip_repository_bzlmod = repository_rule(
- attrs = pip_repository_bzlmod_attrs,
- doc = """A rule for bzlmod pip_repository creation. Intended for private use only.""",
- implementation = _pip_repository_bzlmod_impl,
-)
-
-def _pip_repository_impl(rctx):
- requirements_txt = locked_requirements_label(rctx, rctx.attr)
- content = rctx.read(requirements_txt)
- parsed_requirements_txt = parse_requirements(content)
+ bzl_packages = sorted([normalize_name(name) for name, _ in parsed_requirements_txt.requirements])
- packages = [(normalize_name(name), requirement) for name, requirement in parsed_requirements_txt.requirements]
+ # Normalize cycles first
+ requirement_cycles = {
+ name: sorted(sets.to_list(sets.make(deps)))
+ for name, deps in rctx.attr.experimental_requirement_cycles.items()
+ }
- bzl_packages = sorted([name for name, _ in packages])
+ # Check for conflicts between cycles _before_ we normalize package names so
+ # that reported errors use the names the user specified
+ for i in range(len(requirement_cycles)):
+ left_group = requirement_cycles.keys()[i]
+ left_deps = requirement_cycles.values()[i]
+ for j in range(len(requirement_cycles) - (i + 1)):
+ right_deps = requirement_cycles.values()[1 + i + j]
+ right_group = requirement_cycles.keys()[1 + i + j]
+ for d in left_deps:
+ if d in right_deps:
+ fail("Error: Requirement %s cannot be repeated between cycles %s and %s; please merge the cycles." % (d, left_group, right_group))
+
+ # And normalize the names as used in the cycle specs
+ #
+ # NOTE: We must check that a listed dependency is actually in the actual
+ # requirements set for the current platform so that we can support cycles in
+ # platform-conditional requirements. Otherwise we'll blindly generate a
+ # label referencing a package which may not be installed on the current
+ # platform.
+ requirement_cycles = {
+ normalize_name(name): sorted([normalize_name(d) for d in group if normalize_name(d) in bzl_packages])
+ for name, group in requirement_cycles.items()
+ }
imports = [
- 'load("@rules_python//python/pip_install:pip_repository.bzl", "whl_library")',
+ # NOTE: Maintain the order consistent with `buildifier`
+ 'load("@rules_python//python:pip.bzl", "pip_utils")',
+ 'load("@rules_python//python/pip_install:pip_repository.bzl", "group_library", "whl_library")',
]
annotations = {}
@@ -456,28 +352,37 @@ def _pip_repository_impl(rctx):
if rctx.attr.python_interpreter_target:
config["python_interpreter_target"] = str(rctx.attr.python_interpreter_target)
+ if rctx.attr.experimental_target_platforms:
+ config["experimental_target_platforms"] = rctx.attr.experimental_target_platforms
if rctx.attr.incompatible_generate_aliases:
- _pkg_aliases(rctx, rctx.attr.name, bzl_packages)
+ macro_tmpl = "@%s//{}:{}" % rctx.attr.name
+ aliases = render_pkg_aliases(repo_name = rctx.attr.name, bzl_packages = bzl_packages)
+ for path, contents in aliases.items():
+ rctx.file(path, contents)
+ else:
+ macro_tmpl = "@%s_{}//:{}" % rctx.attr.name
rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS)
rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
"%%ALL_DATA_REQUIREMENTS%%": _format_repr_list([
- "@{}//{}:data".format(rctx.attr.name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:data".format(rctx.attr.name, p)
+ macro_tmpl.format(p, "data")
for p in bzl_packages
]),
"%%ALL_REQUIREMENTS%%": _format_repr_list([
- "@{}//{}".format(rctx.attr.name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:pkg".format(rctx.attr.name, p)
+ macro_tmpl.format(p, "pkg")
for p in bzl_packages
]),
- "%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
- "@{}//{}:whl".format(rctx.attr.name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:whl".format(rctx.attr.name, p)
+ "%%ALL_REQUIREMENT_GROUPS%%": _format_dict(_repr_dict(requirement_cycles)),
+ "%%ALL_WHL_REQUIREMENTS_BY_PACKAGE%%": _format_dict(_repr_dict({
+ p: macro_tmpl.format(p, "whl")
for p in bzl_packages
- ]),
+ })),
"%%ANNOTATIONS%%": _format_dict(_repr_dict(annotations)),
"%%CONFIG%%": _format_dict(_repr_dict(config)),
"%%EXTRA_PIP_ARGS%%": json.encode(options),
- "%%IMPORTS%%": "\n".join(sorted(imports)),
+ "%%IMPORTS%%": "\n".join(imports),
+ "%%MACRO_TMPL%%": macro_tmpl,
"%%NAME%%": rctx.attr.name,
"%%PACKAGES%%": _format_repr_list(
[
@@ -522,6 +427,86 @@ can be passed.
""",
default = {},
),
+ "experimental_requirement_cycles": attr.string_list_dict(
+ default = {},
+ doc = """\
+A mapping of dependency cycle names to a list of requirements which form that cycle.
+
+Requirements which form cycles will be installed together and taken as
+dependencies together in order to ensure that the cycle is always satisified.
+
+Example:
+ `sphinx` depends on `sphinxcontrib-serializinghtml`
+ When listing both as requirements, ala
+
+ ```
+ py_binary(
+ name = "doctool",
+ ...
+ deps = [
+ "@pypi//sphinx:pkg",
+ "@pypi//sphinxcontrib_serializinghtml",
+ ]
+ )
+ ```
+
+ Will produce a Bazel error such as
+
+ ```
+ ERROR: .../external/pypi_sphinxcontrib_serializinghtml/BUILD.bazel:44:6: in alias rule @pypi_sphinxcontrib_serializinghtml//:pkg: cycle in dependency graph:
+ //:doctool (...)
+ @pypi//sphinxcontrib_serializinghtml:pkg (...)
+ .-> @pypi_sphinxcontrib_serializinghtml//:pkg (...)
+ | @pypi_sphinxcontrib_serializinghtml//:_pkg (...)
+ | @pypi_sphinx//:pkg (...)
+ | @pypi_sphinx//:_pkg (...)
+ `-- @pypi_sphinxcontrib_serializinghtml//:pkg (...)
+ ```
+
+ Which we can resolve by configuring these two requirements to be installed together as a cycle
+
+ ```
+ pip_parse(
+ ...
+ experimental_requirement_cycles = {
+ "sphinx": [
+ "sphinx",
+ "sphinxcontrib-serializinghtml",
+ ]
+ },
+ )
+ ```
+
+Warning:
+ If a dependency participates in multiple cycles, all of those cycles must be
+ collapsed down to one. For instance `a <-> b` and `a <-> c` cannot be listed
+ as two separate cycles.
+""",
+ ),
+ "experimental_target_platforms": attr.string_list(
+ default = [],
+ doc = """\
+A list of platforms that we will generate the conditional dependency graph for
+cross platform wheels by parsing the wheel metadata. This will generate the
+correct dependencies for packages like `sphinx` or `pylint`, which include
+`colorama` when installed and used on Windows platforms.
+
+An empty list means falling back to the legacy behaviour where the host
+platform is the target platform.
+
+WARNING: It may not work as expected in cases where the python interpreter
+implementation that is being used at runtime is different between different platforms.
+This has been tested for CPython only.
+
+Special values: `all` (for generating deps for all platforms), `host` (for
+generating deps for the host platform only). `linux_*` and other `<os>_*` values.
+In the future we plan to set `all` as the default to this attribute.
+
+For specific target platforms use values of the form `<os>_<arch>` where `<os>`
+is one of `linux`, `osx`, `windows` and arch is one of `x86_64`, `x86_32`,
+`aarch64`, `s390x` and `ppc64le`.
+""",
+ ),
"extra_pip_args": attr.string_list(
doc = "Extra arguments to pass on to pip. Must not contain spaces.",
),
@@ -580,8 +565,21 @@ pip_repository_attrs = {
doc = "Optional annotations to apply to packages",
),
"incompatible_generate_aliases": attr.bool(
- default = False,
- doc = "Allow generating aliases '@pip//<pkg>' -> '@pip_<pkg>//:pkg'.",
+ default = True,
+ doc = """\
+If true, extra aliases will be created in the main `hub` repo - i.e. the repo
+where the `requirements.bzl` is located. This means that for a Python package
+`PyYAML` initialized within a `pip` `hub_repo` there will be the following
+aliases generated:
+- `@pip//pyyaml` will point to `@pip_pyyaml//:pkg`
+- `@pip//pyyaml:data` will point to `@pip_pyyaml//:data`
+- `@pip//pyyaml:dist_info` will point to `@pip_pyyaml//:dist_info`
+- `@pip//pyyaml:pkg` will point to `@pip_pyyaml//:pkg`
+- `@pip//pyyaml:whl` will point to `@pip_pyyaml//:whl`
+
+This is to keep the dependencies coming from PyPI to have more ergonomic label
+names and support smooth transition to `bzlmod`.
+""",
),
"requirements_darwin": attr.label(
allow_single_file = True,
@@ -593,10 +591,14 @@ pip_repository_attrs = {
),
"requirements_lock": attr.label(
allow_single_file = True,
- doc = """
-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'.
+ doc = """\
+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'. Note that if
+your lockfile is platform-dependent, you can use the `requirements_[platform]`
+attributes.
""",
),
"requirements_windows": attr.label(
@@ -612,22 +614,31 @@ pip_repository_attrs.update(**common_attrs)
pip_repository = repository_rule(
attrs = pip_repository_attrs,
- doc = """A rule for importing `requirements.txt` dependencies into Bazel.
+ doc = """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, see the "vendoring" section below.
+
+In your WORKSPACE file:
-This rule imports a `requirements.txt` file and generates a new
-`requirements.bzl` file. This is used via the `WORKSPACE` pattern:
+```starlark
+load("@rules_python//python:pip.bzl", "pip_parse")
-```python
-pip_repository(
- name = "foo",
- requirements = ":requirements.txt",
+pip_parse(
+ name = "pip_deps",
+ requirements_lock = ":requirements.txt",
)
+
+load("@pip_deps//:requirements.bzl", "install_deps")
+
+install_deps()
```
-You can then reference imported dependencies from your `BUILD` file with:
+You can then reference installed dependencies from a `BUILD` file with:
+
+```starlark
+load("@pip_deps//:requirements.bzl", "requirement")
-```python
-load("@foo//:requirements.bzl", "requirement")
py_library(
name = "bar",
...
@@ -639,17 +650,52 @@ py_library(
)
```
-Or alternatively:
-```python
-load("@foo//:requirements.bzl", "all_requirements")
-py_binary(
- name = "baz",
- ...
- deps = [
- ":foo",
- ] + all_requirements,
+In addition to the `requirement` macro, which is used to access the generated `py_library`
+target generated from a package's wheel, The generated `requirements.bzl` file contains
+functionality for exposing [entry points][whl_ep] as `py_binary` targets as well.
+
+[whl_ep]: https://packaging.python.org/specifications/entry-points/
+
+```starlark
+load("@pip_deps//:requirements.bzl", "entry_point")
+
+alias(
+ name = "pip-compile",
+ actual = entry_point(
+ pkg = "pip-tools",
+ script = "pip-compile",
+ ),
)
```
+
+Note that for packages whose name and script are the same, only the name of the package
+is needed when calling the `entry_point` macro.
+
+```starlark
+load("@pip_deps//:requirements.bzl", "entry_point")
+
+alias(
+ name = "flake8",
+ actual = entry_point("flake8"),
+)
+```
+
+### Vendoring the requirements.bzl file
+
+In some cases you may not want to generate the requirements.bzl file as a repository rule
+while Bazel is fetching dependencies. For example, if you produce a reusable Bazel module
+such as a ruleset, you may want to include the requirements.bzl file rather than make your users
+install the WORKSPACE setup to generate it.
+See https://github.com/bazelbuild/rules_python/issues/608
+
+This is the same workflow as Gazelle, which creates `go_repository` rules with
+[`update-repos`](https://github.com/bazelbuild/bazel-gazelle#update-repos)
+
+To do this, use the "write to source file" pattern documented in
+https://blog.aspect.dev/bazel-can-write-to-the-source-folder
+to put a copy of the generated requirements.bzl into your project.
+Then load the requirements.bzl file directly rather than from the generated repository.
+See the example in rules_python/examples/pip_parse_vendored.
""",
implementation = _pip_repository_impl,
environ = common_env,
@@ -663,23 +709,59 @@ def _whl_library_impl(rctx):
"python.pip_install.tools.wheel_installer.wheel_installer",
"--requirement",
rctx.attr.requirement,
- "--repo",
- rctx.attr.repo,
- "--repo-prefix",
- rctx.attr.repo_prefix,
]
- if rctx.attr.annotation:
- args.extend([
- "--annotation",
- rctx.path(rctx.attr.annotation),
- ])
args = _parse_optional_attrs(rctx, args)
+ # Manually construct the PYTHONPATH since we cannot use the toolchain here
+ environment = _create_repository_execution_environment(rctx, python_interpreter)
+
result = rctx.execute(
args,
- # Manually construct the PYTHONPATH since we cannot use the toolchain here
- environment = _create_repository_execution_environment(rctx),
+ environment = environment,
+ quiet = rctx.attr.quiet,
+ timeout = rctx.attr.timeout,
+ )
+ if result.return_code:
+ fail("whl_library %s failed: %s (%s) error code: '%s'" % (rctx.attr.name, result.stdout, result.stderr, result.return_code))
+
+ whl_path = rctx.path(json.decode(rctx.read("whl_file.json"))["whl_file"])
+ if not rctx.delete("whl_file.json"):
+ fail("failed to delete the whl_file.json file")
+
+ if rctx.attr.whl_patches:
+ patches = {}
+ for patch_file, json_args in rctx.attr.whl_patches.items():
+ patch_dst = struct(**json.decode(json_args))
+ if whl_path.basename in patch_dst.whls:
+ patches[patch_file] = patch_dst.patch_strip
+
+ whl_path = patch_whl(
+ rctx,
+ python_interpreter = python_interpreter,
+ whl_path = whl_path,
+ patches = patches,
+ quiet = rctx.attr.quiet,
+ timeout = rctx.attr.timeout,
+ )
+
+ target_platforms = rctx.attr.experimental_target_platforms
+ if target_platforms:
+ parsed_whl = parse_whl_name(whl_path.basename)
+ if parsed_whl.platform_tag != "any":
+ # NOTE @aignas 2023-12-04: if the wheel is a platform specific
+ # wheel, we only include deps for that target platform
+ target_platforms = [
+ "{}_{}".format(p.os, p.cpu)
+ for p in whl_target_platforms(parsed_whl.platform_tag)
+ ]
+
+ result = rctx.execute(
+ args + [
+ "--whl-file",
+ whl_path,
+ ] + ["--platform={}".format(p) for p in target_platforms],
+ environment = environment,
quiet = rctx.attr.quiet,
timeout = rctx.attr.timeout,
)
@@ -687,8 +769,76 @@ def _whl_library_impl(rctx):
if result.return_code:
fail("whl_library %s failed: %s (%s) error code: '%s'" % (rctx.attr.name, result.stdout, result.stderr, result.return_code))
+ metadata = json.decode(rctx.read("metadata.json"))
+ rctx.delete("metadata.json")
+
+ entry_points = {}
+ for item in metadata["entry_points"]:
+ name = item["name"]
+ module = item["module"]
+ attribute = item["attribute"]
+
+ # There is an extreme edge-case with entry_points that end with `.py`
+ # See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174
+ entry_point_without_py = name[:-3] + "_py" if name.endswith(".py") else name
+ entry_point_target_name = (
+ _WHEEL_ENTRY_POINT_PREFIX + "_" + entry_point_without_py
+ )
+ entry_point_script_name = entry_point_target_name + ".py"
+
+ rctx.file(
+ entry_point_script_name,
+ _generate_entry_point_contents(module, attribute),
+ )
+ entry_points[entry_point_without_py] = entry_point_script_name
+
+ build_file_contents = generate_whl_library_build_bazel(
+ repo_prefix = rctx.attr.repo_prefix,
+ whl_name = whl_path.basename,
+ dependencies = metadata["deps"],
+ dependencies_by_platform = metadata["deps_by_platform"],
+ group_name = rctx.attr.group_name,
+ group_deps = rctx.attr.group_deps,
+ data_exclude = rctx.attr.pip_data_exclude,
+ tags = [
+ "pypi_name=" + metadata["name"],
+ "pypi_version=" + metadata["version"],
+ ],
+ entry_points = entry_points,
+ annotation = None if not rctx.attr.annotation else struct(**json.decode(rctx.read(rctx.attr.annotation))),
+ )
+ rctx.file("BUILD.bazel", build_file_contents)
+
return
+def _generate_entry_point_contents(
+ module,
+ attribute,
+ shebang = "#!/usr/bin/env python3"):
+ """Generate the contents of an entry point script.
+
+ Args:
+ module (str): The name of the module to use.
+ attribute (str): The name of the attribute to call.
+ shebang (str, optional): The shebang to use for the entry point python
+ file.
+
+ Returns:
+ str: A string of python code.
+ """
+ contents = """\
+{shebang}
+import sys
+from {module} import {attribute}
+if __name__ == "__main__":
+ sys.exit({attribute}())
+""".format(
+ shebang = shebang,
+ module = module,
+ attribute = attribute,
+ )
+ return contents
+
whl_library_attrs = {
"annotation": attr.label(
doc = (
@@ -697,6 +847,13 @@ whl_library_attrs = {
),
allow_files = True,
),
+ "group_deps": attr.string_list(
+ doc = "List of dependencies to skip in order to break the cycles within a dependency group.",
+ default = [],
+ ),
+ "group_name": attr.string(
+ doc = "Name of the group, if any.",
+ ),
"repo": attr.string(
mandatory = True,
doc = "Pointer to parent repo name. Used to make these rules rerun if the parent repo changes.",
@@ -705,6 +862,26 @@ whl_library_attrs = {
mandatory = True,
doc = "Python requirement string describing the package to make available",
),
+ "whl_patches": attr.label_keyed_string_dict(
+ doc = """a label-keyed-string dict that has
+ json.encode(struct([whl_file], patch_strip]) as values. This
+ is to maintain flexibility and correct bzlmod extension interface
+ until we have a better way to define whl_library and move whl
+ patching to a separate place. INTERNAL USE ONLY.""",
+ ),
+ "_python_path_entries": attr.label_list(
+ # Get the root directory of these rules and keep them as a default attribute
+ # in order to avoid unnecessary repository fetching restarts.
+ #
+ # This is very similar to what was done in https://github.com/bazelbuild/rules_go/pull/3478
+ default = [
+ Label("//:BUILD.bazel"),
+ ] + [
+ # Includes all the external dependencies from repositories.bzl
+ Label("@" + repo + "//:BUILD.bazel")
+ for repo in all_requirements
+ ],
+ ),
}
whl_library_attrs.update(**common_attrs)
@@ -752,6 +929,29 @@ def package_annotation(
srcs_exclude_glob = srcs_exclude_glob,
))
+def _group_library_impl(rctx):
+ build_file_contents = generate_group_library_build_bazel(
+ repo_prefix = rctx.attr.repo_prefix,
+ groups = rctx.attr.groups,
+ )
+ rctx.file("BUILD.bazel", build_file_contents)
+
+group_library = repository_rule(
+ attrs = {
+ "groups": attr.string_list_dict(
+ doc = "A mapping of group names to requirements within that group.",
+ ),
+ "repo_prefix": attr.string(
+ doc = "Prefix used for the whl_library created components of each group",
+ ),
+ },
+ implementation = _group_library_impl,
+ doc = """
+Create a package containing only wrapper py_library and whl_library rules for implementing dependency groups.
+This is an implementation detail of dependency groups and should not be used alone.
+ """,
+)
+
# pip_repository implementation
def _format_list(items):
diff --git a/python/pip_install/pip_repository_requirements.bzl.tmpl b/python/pip_install/pip_repository_requirements.bzl.tmpl
index 411f334..2b88f5c 100644
--- a/python/pip_install/pip_repository_requirements.bzl.tmpl
+++ b/python/pip_install/pip_repository_requirements.bzl.tmpl
@@ -8,7 +8,9 @@ from %%REQUIREMENTS_LOCK%%
all_requirements = %%ALL_REQUIREMENTS%%
-all_whl_requirements = %%ALL_WHL_REQUIREMENTS%%
+all_whl_requirements_by_package = %%ALL_WHL_REQUIREMENTS_BY_PACKAGE%%
+
+all_whl_requirements = all_whl_requirements_by_package.values()
all_data_requirements = %%ALL_DATA_REQUIREMENTS%%
@@ -16,25 +18,22 @@ _packages = %%PACKAGES%%
_config = %%CONFIG%%
_annotations = %%ANNOTATIONS%%
-def _clean_name(name):
- return name.replace("-", "_").replace(".", "_").lower()
-
def requirement(name):
- return "@%%NAME%%_" + _clean_name(name) + "//:pkg"
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "pkg")
def whl_requirement(name):
- return "@%%NAME%%_" + _clean_name(name) + "//:whl"
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "whl")
def data_requirement(name):
- return "@%%NAME%%_" + _clean_name(name) + "//:data"
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "data")
def dist_info_requirement(name):
- return "@%%NAME%%_" + _clean_name(name) + "//:dist_info"
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "dist_info")
def entry_point(pkg, script = None):
if not script:
script = pkg
- return "@%%NAME%%_" + _clean_name(pkg) + "//:rules_python_wheel_entry_point_" + script
+ return "@%%NAME%%_" + pip_utils.normalize_name(pkg) + "//:rules_python_wheel_entry_point_" + script
def _get_annotation(requirement):
# This expects to parse `setuptools==58.2.0 --hash=sha256:2551203ae6955b9876741a26ab3e767bb3242dafe86a32a749ea0d78b6792f11`
@@ -43,12 +42,42 @@ def _get_annotation(requirement):
return _annotations.get(name)
def install_deps(**whl_library_kwargs):
+ """Repository rule macro. Install dependencies from `pip_parse`.
+
+ Args:
+ **whl_library_kwargs: Additional arguments which will flow to underlying
+ `whl_library` calls. See pip_repository.bzl for details.
+ """
+
+ # Set up the requirement groups
+ all_requirement_groups = %%ALL_REQUIREMENT_GROUPS%%
+
+ requirement_group_mapping = {
+ requirement: group_name
+ for group_name, group_requirements in all_requirement_groups.items()
+ for requirement in group_requirements
+ }
+
+ group_repo = "%%NAME%%__groups"
+ group_library(
+ name = group_repo,
+ repo_prefix = "%%NAME%%_",
+ groups = all_requirement_groups,
+ )
+
+ # Install wheels which may be participants in a group
whl_config = dict(_config)
whl_config.update(whl_library_kwargs)
+
for name, requirement in _packages:
+ group_name = requirement_group_mapping.get(name.replace("%%NAME%%_", ""))
+ group_deps = all_requirement_groups.get(group_name, [])
+
whl_library(
name = name,
requirement = requirement,
+ group_name = group_name,
+ group_deps = group_deps,
annotation = _get_annotation(requirement),
**whl_config
)
diff --git a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl
deleted file mode 100644
index 2df60b0..0000000
--- a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl
+++ /dev/null
@@ -1,33 +0,0 @@
-"""Starlark representation of locked requirements.
-
-@generated by rules_python pip_parse repository rule
-from %%REQUIREMENTS_LOCK%%.
-"""
-
-all_requirements = %%ALL_REQUIREMENTS%%
-
-all_whl_requirements = %%ALL_WHL_REQUIREMENTS%%
-
-all_data_requirements = %%ALL_DATA_REQUIREMENTS%%
-
-def _clean_name(name):
- return name.replace("-", "_").replace(".", "_").lower()
-
-def requirement(name):
- return "%%MACRO_TMPL%%".format(_clean_name(name), "pkg")
-
-def whl_requirement(name):
- return "%%MACRO_TMPL%%".format(_clean_name(name), "whl")
-
-def data_requirement(name):
- return "%%MACRO_TMPL%%".format(_clean_name(name), "data")
-
-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)
diff --git a/python/pip_install/private/BUILD.bazel b/python/pip_install/private/BUILD.bazel
index 86b4b3d..887d2d3 100644
--- a/python/pip_install/private/BUILD.bazel
+++ b/python/pip_install/private/BUILD.bazel
@@ -1,3 +1,4 @@
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load(":pip_install_utils.bzl", "srcs_module")
package(default_visibility = ["//:__subpackages__"])
@@ -22,3 +23,26 @@ srcs_module(
srcs = "//python/pip_install:py_srcs",
dest = ":srcs.bzl",
)
+
+bzl_library(
+ name = "generate_whl_library_build_bazel_bzl",
+ srcs = ["generate_whl_library_build_bazel.bzl"],
+ deps = [
+ "//python/private:labels_bzl",
+ "//python/private:normalize_name_bzl",
+ ],
+)
+
+bzl_library(
+ name = "generate_group_library_build_bazel_bzl",
+ srcs = ["generate_group_library_build_bazel.bzl"],
+ deps = [
+ "//python/private:labels_bzl",
+ "//python/private:normalize_name_bzl",
+ ],
+)
+
+bzl_library(
+ name = "srcs_bzl",
+ srcs = ["srcs.bzl"],
+)
diff --git a/python/pip_install/private/generate_group_library_build_bazel.bzl b/python/pip_install/private/generate_group_library_build_bazel.bzl
new file mode 100644
index 0000000..c122b04
--- /dev/null
+++ b/python/pip_install/private/generate_group_library_build_bazel.bzl
@@ -0,0 +1,105 @@
+# 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.
+
+"""Generate the BUILD.bazel contents for a repo defined by a group_library."""
+
+load(
+ "//python/private:labels.bzl",
+ "PY_LIBRARY_IMPL_LABEL",
+ "PY_LIBRARY_PUBLIC_LABEL",
+ "WHEEL_FILE_IMPL_LABEL",
+ "WHEEL_FILE_PUBLIC_LABEL",
+)
+load("//python/private:normalize_name.bzl", "normalize_name")
+
+_PRELUDE = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+"""
+
+_GROUP_TEMPLATE = """\
+## Group {name}
+
+filegroup(
+ name = "{name}_{whl_public_label}",
+ srcs = [],
+ data = {whl_deps},
+ visibility = {visibility},
+)
+
+py_library(
+ name = "{name}_{lib_public_label}",
+ srcs = [],
+ deps = {lib_deps},
+ visibility = {visibility},
+)
+"""
+
+def _generate_group_libraries(repo_prefix, group_name, group_members):
+ """Generate the component libraries implementing a group.
+
+ A group consists of two underlying composite libraries, one `filegroup`
+ which wraps all the whls of the members and one `py_library` which wraps the
+ pkgs of the members.
+
+ Implementation detail of `generate_group_library_build_bazel` which uses
+ this to construct a BUILD.bazel.
+
+ Args:
+ repo_prefix: str; the pip_parse repo prefix.
+ group_name: str; the name which the user provided for the dep group.
+ group_members: list[str]; the names of the _packages_ (not repositories)
+ which make up the group.
+ """
+
+ lib_dependencies = [
+ "@%s%s//:%s" % (repo_prefix, normalize_name(d), PY_LIBRARY_IMPL_LABEL)
+ for d in group_members
+ ]
+ whl_file_deps = [
+ "@%s%s//:%s" % (repo_prefix, normalize_name(d), WHEEL_FILE_IMPL_LABEL)
+ for d in group_members
+ ]
+ visibility = [
+ "@%s%s//:__pkg__" % (repo_prefix, normalize_name(d))
+ for d in group_members
+ ]
+
+ return _GROUP_TEMPLATE.format(
+ name = normalize_name(group_name),
+ whl_public_label = WHEEL_FILE_PUBLIC_LABEL,
+ whl_deps = repr(whl_file_deps),
+ lib_public_label = PY_LIBRARY_PUBLIC_LABEL,
+ lib_deps = repr(lib_dependencies),
+ visibility = repr(visibility),
+ )
+
+def generate_group_library_build_bazel(
+ repo_prefix,
+ groups):
+ """Generate a BUILD file for a repository of group implementations
+
+ Args:
+ repo_prefix: the repo prefix that should be used for dependency lists.
+ groups: a mapping of group names to lists of names of component packages.
+
+ Returns:
+ A complete BUILD file as a string
+ """
+
+ content = [_PRELUDE]
+
+ for group_name, group_members in groups.items():
+ content.append(_generate_group_libraries(repo_prefix, group_name, group_members))
+
+ return "\n\n".join(content)
diff --git a/python/pip_install/private/generate_whl_library_build_bazel.bzl b/python/pip_install/private/generate_whl_library_build_bazel.bzl
new file mode 100644
index 0000000..568b00e
--- /dev/null
+++ b/python/pip_install/private/generate_whl_library_build_bazel.bzl
@@ -0,0 +1,344 @@
+# 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.
+
+"""Generate the BUILD.bazel contents for a repo defined by a whl_library."""
+
+load(
+ "//python/private:labels.bzl",
+ "DATA_LABEL",
+ "DIST_INFO_LABEL",
+ "PY_LIBRARY_IMPL_LABEL",
+ "PY_LIBRARY_PUBLIC_LABEL",
+ "WHEEL_ENTRY_POINT_PREFIX",
+ "WHEEL_FILE_IMPL_LABEL",
+ "WHEEL_FILE_PUBLIC_LABEL",
+)
+load("//python/private:normalize_name.bzl", "normalize_name")
+load("//python/private:text_util.bzl", "render")
+
+_COPY_FILE_TEMPLATE = """\
+copy_file(
+ name = "{dest}.copy",
+ src = "{src}",
+ out = "{dest}",
+ is_executable = {is_executable},
+)
+"""
+
+_ENTRY_POINT_RULE_TEMPLATE = """\
+py_binary(
+ name = "{name}",
+ srcs = ["{src}"],
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["."],
+ deps = ["{pkg}"],
+)
+"""
+
+_BUILD_TEMPLATE = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "{dist_info_label}",
+ srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "{data_label}",
+ srcs = glob(["data/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "{whl_file_impl_label}",
+ srcs = ["{whl_name}"],
+ data = {whl_file_deps},
+ visibility = {impl_vis},
+)
+
+py_library(
+ name = "{py_library_impl_label}",
+ srcs = glob(
+ ["site-packages/**/*.py"],
+ exclude={srcs_exclude},
+ # Empty sources are allowed to support wheels that don't have any
+ # pure-Python code, e.g. pymssql, which is written in Cython.
+ allow_empty = True,
+ ),
+ data = {data} + glob(
+ ["site-packages/**/*"],
+ exclude={data_exclude},
+ ),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["site-packages"],
+ deps = {dependencies},
+ tags = {tags},
+ visibility = {impl_vis},
+)
+
+alias(
+ name = "{py_library_public_label}",
+ actual = "{py_library_actual_label}",
+)
+
+alias(
+ name = "{whl_file_public_label}",
+ actual = "{whl_file_actual_label}",
+)
+"""
+
+def _render_list_and_select(deps, deps_by_platform, tmpl):
+ deps = render.list([tmpl.format(d) for d in deps])
+
+ if not deps_by_platform:
+ return deps
+
+ deps_by_platform = {
+ p if p.startswith("@") else ":is_" + p: [
+ tmpl.format(d)
+ for d in deps
+ ]
+ for p, deps in deps_by_platform.items()
+ }
+
+ # Add the default, which means that we will be just using the dependencies in
+ # `deps` for platforms that are not handled in a special way by the packages
+ deps_by_platform["//conditions:default"] = []
+ deps_by_platform = render.select(deps_by_platform, value_repr = render.list)
+
+ if deps == "[]":
+ return deps_by_platform
+ else:
+ return "{} + {}".format(deps, deps_by_platform)
+
+def generate_whl_library_build_bazel(
+ *,
+ repo_prefix,
+ whl_name,
+ dependencies,
+ dependencies_by_platform,
+ data_exclude,
+ tags,
+ entry_points,
+ annotation = None,
+ group_name = None,
+ group_deps = []):
+ """Generate a BUILD file for an unzipped Wheel
+
+ Args:
+ repo_prefix: the repo prefix that should be used for dependency lists.
+ whl_name: the whl_name that this is generated for.
+ dependencies: a list of PyPI packages that are dependencies to the py_library.
+ dependencies_by_platform: a dict[str, list] of PyPI packages that may vary by platform.
+ data_exclude: more patterns to exclude from the data attribute of generated py_library rules.
+ tags: list of tags to apply to generated py_library rules.
+ entry_points: A dict of entry points to add py_binary rules for.
+ annotation: The annotation for the build file.
+ group_name: Optional[str]; name of the dependency group (if any) which contains this library.
+ If set, this library will behave as a shim to group implementation rules which will provide
+ simultaneously installed dependencies which would otherwise form a cycle.
+ group_deps: List[str]; names of fellow members of the group (if any). These will be excluded
+ from generated deps lists so as to avoid direct cycles. These dependencies will be provided
+ at runtime by the group rules which wrap this library and its fellows together.
+
+ Returns:
+ A complete BUILD file as a string
+ """
+
+ additional_content = []
+ data = []
+ srcs_exclude = []
+ data_exclude = [] + data_exclude
+ dependencies = sorted([normalize_name(d) for d in dependencies])
+ dependencies_by_platform = {
+ platform: sorted([normalize_name(d) for d in deps])
+ for platform, deps in dependencies_by_platform.items()
+ }
+ tags = sorted(tags)
+
+ for entry_point, entry_point_script_name in entry_points.items():
+ additional_content.append(
+ _generate_entry_point_rule(
+ name = "{}_{}".format(WHEEL_ENTRY_POINT_PREFIX, entry_point),
+ script = entry_point_script_name,
+ pkg = ":" + PY_LIBRARY_PUBLIC_LABEL,
+ ),
+ )
+
+ if annotation:
+ for src, dest in annotation.copy_files.items():
+ data.append(dest)
+ additional_content.append(_generate_copy_commands(src, dest))
+ for src, dest in annotation.copy_executables.items():
+ data.append(dest)
+ additional_content.append(
+ _generate_copy_commands(src, dest, is_executable = True),
+ )
+ data.extend(annotation.data)
+ data_exclude.extend(annotation.data_exclude_glob)
+ srcs_exclude.extend(annotation.srcs_exclude_glob)
+ if annotation.additive_build_content:
+ additional_content.append(annotation.additive_build_content)
+
+ _data_exclude = [
+ "**/* *",
+ "**/*.py",
+ "**/*.pyc",
+ "**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNNN are created
+ # RECORD is known to contain sha256 checksums of files which might include the checksums
+ # of generated files produced when wheels are installed. The file is ignored to avoid
+ # Bazel caching issues.
+ "**/*.dist-info/RECORD",
+ ]
+ for item in data_exclude:
+ if item not in _data_exclude:
+ _data_exclude.append(item)
+
+ # Ensure this list is normalized
+ # Note: mapping used as set
+ group_deps = {
+ normalize_name(d): True
+ for d in group_deps
+ }
+
+ dependencies = [
+ d
+ for d in dependencies
+ if d not in group_deps
+ ]
+ dependencies_by_platform = {
+ p: deps
+ for p, deps in dependencies_by_platform.items()
+ for deps in [[d for d in deps if d not in group_deps]]
+ if deps
+ }
+
+ for p in dependencies_by_platform:
+ if p.startswith("@"):
+ continue
+
+ os, _, cpu = p.partition("_")
+
+ additional_content.append(
+ """\
+config_setting(
+ name = "is_{os}_{cpu}",
+ constraint_values = [
+ "@platforms//cpu:{cpu}",
+ "@platforms//os:{os}",
+ ],
+ visibility = ["//visibility:private"],
+)
+""".format(os = os, cpu = cpu),
+ )
+
+ lib_dependencies = _render_list_and_select(
+ deps = dependencies,
+ deps_by_platform = dependencies_by_platform,
+ tmpl = "@{}{{}}//:{}".format(repo_prefix, PY_LIBRARY_PUBLIC_LABEL),
+ )
+
+ whl_file_deps = _render_list_and_select(
+ deps = dependencies,
+ deps_by_platform = dependencies_by_platform,
+ tmpl = "@{}{{}}//:{}".format(repo_prefix, WHEEL_FILE_PUBLIC_LABEL),
+ )
+
+ # If this library is a member of a group, its public label aliases need to
+ # point to the group implementation rule not the implementation rules. We
+ # also need to mark the implementation rules as visible to the group
+ # implementation.
+ if group_name:
+ group_repo = repo_prefix + "_groups"
+ library_impl_label = "@%s//:%s_%s" % (group_repo, normalize_name(group_name), PY_LIBRARY_PUBLIC_LABEL)
+ whl_impl_label = "@%s//:%s_%s" % (group_repo, normalize_name(group_name), WHEEL_FILE_PUBLIC_LABEL)
+ impl_vis = "@%s//:__pkg__" % (group_repo,)
+
+ else:
+ library_impl_label = PY_LIBRARY_IMPL_LABEL
+ whl_impl_label = WHEEL_FILE_IMPL_LABEL
+ impl_vis = "//visibility:private"
+
+ contents = "\n".join(
+ [
+ _BUILD_TEMPLATE.format(
+ py_library_public_label = PY_LIBRARY_PUBLIC_LABEL,
+ py_library_impl_label = PY_LIBRARY_IMPL_LABEL,
+ py_library_actual_label = library_impl_label,
+ dependencies = render.indent(lib_dependencies, " " * 4).lstrip(),
+ whl_file_deps = render.indent(whl_file_deps, " " * 4).lstrip(),
+ data_exclude = repr(_data_exclude),
+ whl_name = whl_name,
+ whl_file_public_label = WHEEL_FILE_PUBLIC_LABEL,
+ whl_file_impl_label = WHEEL_FILE_IMPL_LABEL,
+ whl_file_actual_label = whl_impl_label,
+ tags = repr(tags),
+ data_label = DATA_LABEL,
+ dist_info_label = DIST_INFO_LABEL,
+ entry_point_prefix = WHEEL_ENTRY_POINT_PREFIX,
+ srcs_exclude = repr(srcs_exclude),
+ data = repr(data),
+ impl_vis = repr([impl_vis]),
+ ),
+ ] + additional_content,
+ )
+
+ # NOTE: Ensure that we terminate with a new line
+ return contents.rstrip() + "\n"
+
+def _generate_copy_commands(src, dest, is_executable = False):
+ """Generate a [@bazel_skylib//rules:copy_file.bzl%copy_file][cf] target
+
+ [cf]: https://github.com/bazelbuild/bazel-skylib/blob/1.1.1/docs/copy_file_doc.md
+
+ Args:
+ src (str): The label for the `src` attribute of [copy_file][cf]
+ dest (str): The label for the `out` attribute of [copy_file][cf]
+ is_executable (bool, optional): Whether or not the file being copied is executable.
+ sets `is_executable` for [copy_file][cf]
+
+ Returns:
+ str: A `copy_file` instantiation.
+ """
+ return _COPY_FILE_TEMPLATE.format(
+ src = src,
+ dest = dest,
+ is_executable = is_executable,
+ )
+
+def _generate_entry_point_rule(*, name, script, pkg):
+ """Generate a Bazel `py_binary` rule for an entry point script.
+
+ Note that the script is used to determine the name of the target. The name of
+ entry point targets should be uniuqe to avoid conflicts with existing sources or
+ directories within a wheel.
+
+ Args:
+ name (str): The name of the generated py_binary.
+ script (str): The path to the entry point's python file.
+ pkg (str): The package owning the entry point. This is expected to
+ match up with the `py_library` defined for each repository.
+
+ Returns:
+ str: A `py_binary` instantiation.
+ """
+ return _ENTRY_POINT_RULE_TEMPLATE.format(
+ name = name,
+ src = script.replace("\\", "/"),
+ pkg = pkg,
+ )
diff --git a/python/pip_install/private/srcs.bzl b/python/pip_install/private/srcs.bzl
index f3064a3..e92e49f 100644
--- a/python/pip_install/private/srcs.bzl
+++ b/python/pip_install/private/srcs.bzl
@@ -9,11 +9,10 @@ This file is auto-generated from the `@rules_python//python/pip_install/private:
PIP_INSTALL_PY_SRCS = [
"@rules_python//python/pip_install/tools/dependency_resolver:__init__.py",
"@rules_python//python/pip_install/tools/dependency_resolver:dependency_resolver.py",
- "@rules_python//python/pip_install/tools/lib:__init__.py",
- "@rules_python//python/pip_install/tools/lib:annotation.py",
- "@rules_python//python/pip_install/tools/lib:arguments.py",
- "@rules_python//python/pip_install/tools/lib:bazel.py",
+ "@rules_python//python/pip_install/tools/wheel_installer:arguments.py",
"@rules_python//python/pip_install/tools/wheel_installer:namespace_pkgs.py",
"@rules_python//python/pip_install/tools/wheel_installer:wheel.py",
"@rules_python//python/pip_install/tools/wheel_installer:wheel_installer.py",
+ "@rules_python//python/private:repack_whl.py",
+ "@rules_python//tools:wheelmaker.py",
]
diff --git a/python/pip_install/repositories.bzl b/python/pip_install/repositories.bzl
index efe3bc7..91bdd4b 100644
--- a/python/pip_install/repositories.bzl
+++ b/python/pip_install/repositories.bzl
@@ -14,21 +14,20 @@
""
-load("@bazel_skylib//lib:versions.bzl", "versions")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
-load("//:version.bzl", "MINIMUM_BAZEL_VERSION")
_RULE_DEPS = [
+ # START: maintained by 'bazel run //tools/private:update_pip_deps'
(
"pypi__build",
- "https://files.pythonhosted.org/packages/03/97/f58c723ff036a8d8b4d3115377c0a37ed05c1f68dd9a0d66dab5e82c5c1c/build-0.9.0-py3-none-any.whl",
- "38a7a2b7a0bdc61a42a0a67509d88c71ecfc37b393baba770fae34e20929ff69",
+ "https://files.pythonhosted.org/packages/58/91/17b00d5fac63d3dca605f1b8269ba3c65e98059e1fd99d00283e42a454f0/build-0.10.0-py3-none-any.whl",
+ "af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171",
),
(
"pypi__click",
- "https://files.pythonhosted.org/packages/76/0a/b6c5f311e32aeb3b406e03c079ade51e905ea630fc19d1262a46249c1c86/click-8.0.1-py3-none-any.whl",
- "fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6",
+ "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
+ "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
),
(
"pypi__colorama",
@@ -36,14 +35,24 @@ _RULE_DEPS = [
"4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
),
(
+ "pypi__importlib_metadata",
+ "https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl",
+ "3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb",
+ ),
+ (
"pypi__installer",
"https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
"05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
),
(
+ "pypi__more_itertools",
+ "https://files.pythonhosted.org/packages/5a/cb/6dce742ea14e47d6f565589e859ad225f2a5de576d7696e0623b784e226b/more_itertools-10.1.0-py3-none-any.whl",
+ "64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6",
+ ),
+ (
"pypi__packaging",
- "https://files.pythonhosted.org/packages/8f/7b/42582927d281d7cb035609cd3a543ffac89b74f3f4ee8e1c50914bcb57eb/packaging-22.0-py3-none-any.whl",
- "957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3",
+ "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl",
+ "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
),
(
"pypi__pep517",
@@ -52,18 +61,23 @@ _RULE_DEPS = [
),
(
"pypi__pip",
- "https://files.pythonhosted.org/packages/09/bd/2410905c76ee14c62baf69e3f4aa780226c1bbfc9485731ad018e35b0cb5/pip-22.3.1-py3-none-any.whl",
- "908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077",
+ "https://files.pythonhosted.org/packages/50/c2/e06851e8cc28dcad7c155f4753da8833ac06a5c704c109313b8d5a62968a/pip-23.2.1-py3-none-any.whl",
+ "7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be",
),
(
"pypi__pip_tools",
- "https://files.pythonhosted.org/packages/5e/e8/f6d7d1847c7351048da870417724ace5c4506e816b38db02f4d7c675c189/pip_tools-6.12.1-py3-none-any.whl",
- "f0c0c0ec57b58250afce458e2e6058b1f30a4263db895b7d72fd6311bf1dc6f7",
+ "https://files.pythonhosted.org/packages/e8/df/47e6267c6b5cdae867adbdd84b437393e6202ce4322de0a5e0b92960e1d6/pip_tools-7.3.0-py3-none-any.whl",
+ "8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e",
+ ),
+ (
+ "pypi__pyproject_hooks",
+ "https://files.pythonhosted.org/packages/d5/ea/9ae603de7fbb3df820b23a70f6aff92bf8c7770043254ad8d2dc9d6bcba4/pyproject_hooks-1.0.0-py3-none-any.whl",
+ "283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8",
),
(
"pypi__setuptools",
- "https://files.pythonhosted.org/packages/7c/5b/3d92b9f0f7ca1645cba48c080b54fe7d8b1033a4e5720091d1631c4266db/setuptools-60.10.0-py3-none-any.whl",
- "782ef48d58982ddb49920c11a0c5c9c0b02e7d7d1c2ad0aa44e1a1e133051c96",
+ "https://files.pythonhosted.org/packages/4f/ab/0bcfebdfc3bfa8554b2b2c97a555569c4c1ebc74ea288741ea8326c51906/setuptools-68.1.2-py3-none-any.whl",
+ "3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b",
),
(
"pypi__tomli",
@@ -72,24 +86,15 @@ _RULE_DEPS = [
),
(
"pypi__wheel",
- "https://files.pythonhosted.org/packages/bd/7c/d38a0b30ce22fc26ed7dbc087c6d00851fb3395e9d0dac40bec1f905030c/wheel-0.38.4-py3-none-any.whl",
- "b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8",
- ),
- (
- "pypi__importlib_metadata",
- "https://files.pythonhosted.org/packages/d7/31/74dcb59a601b95fce3b0334e8fc9db758f78e43075f22aeb3677dfb19f4c/importlib_metadata-1.4.0-py2.py3-none-any.whl",
- "bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359",
+ "https://files.pythonhosted.org/packages/b8/8b/31273bf66016be6ad22bb7345c37ff350276cfd46e389a0c2ac5da9d9073/wheel-0.41.2-py3-none-any.whl",
+ "75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8",
),
(
"pypi__zipp",
- "https://files.pythonhosted.org/packages/f4/50/cc72c5bcd48f6e98219fc4a88a5227e9e28b81637a99c49feba1d51f4d50/zipp-1.0.0-py2.py3-none-any.whl",
- "8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656",
- ),
- (
- "pypi__more_itertools",
- "https://files.pythonhosted.org/packages/bd/3f/c4b3dbd315e248f84c388bd4a72b131a29f123ecacc37ffb2b3834546e42/more_itertools-8.13.0-py3-none-any.whl",
- "c5122bffc5f104d37c1626b8615b511f3427aa5389b94d61e5ef8236bfbc3ddb",
+ "https://files.pythonhosted.org/packages/8c/08/d3006317aefe25ea79d3b76c9650afabaf6d63d1c8443b236e7405447503/zipp-3.16.2-py3-none-any.whl",
+ "679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0",
),
+ # END: maintained by 'bazel run //tools/private:update_pip_deps'
]
_GENERIC_WHEEL = """\
@@ -126,17 +131,8 @@ def requirement(pkg):
def pip_install_dependencies():
"""
- Fetch dependencies these rules depend on. Workspaces that use the pip_install rule can call this.
-
- (However we call it from pip_install, making it optional for users to do so.)
+ Fetch dependencies these rules depend on. Workspaces that use the pip_parse rule can call this.
"""
-
- # We only support Bazel LTS and rolling releases.
- # Give the user an obvious error to upgrade rather than some obscure missing symbol later.
- # It's not guaranteed that users call this function, but it's used by all the pip fetch
- # repository rules so it's likely that most users get the right error.
- versions.check(MINIMUM_BAZEL_VERSION)
-
for (name, url, sha256) in _RULE_DEPS:
maybe(
http_archive,
diff --git a/python/pip_install/requirements.bzl b/python/pip_install/requirements.bzl
index 84ee203..5caf762 100644
--- a/python/pip_install/requirements.bzl
+++ b/python/pip_install/requirements.bzl
@@ -19,6 +19,7 @@ load("//python/pip_install:repositories.bzl", "requirement")
def compile_pip_requirements(
name,
+ src = None,
extra_args = [],
extra_deps = [],
generate_hashes = True,
@@ -48,12 +49,17 @@ def compile_pip_requirements(
Args:
name: base name for generated targets, typically "requirements".
+ src: file containing inputs to dependency resolution. If not specified,
+ defaults to `pyproject.toml`. Supported formats are:
+ * a requirements text file, usually named `requirements.in`
+ * A `.toml` file, where the `project.dependencies` list is used as per
+ [PEP621](https://peps.python.org/pep-0621/).
extra_args: passed to pip-compile.
extra_deps: extra dependencies passed to pip-compile.
generate_hashes: whether to put hashes in the requirements_txt file.
py_binary: the py_binary rule to be used.
py_test: the py_test rule to be used.
- requirements_in: file expressing desired dependencies.
+ requirements_in: file expressing desired dependencies. Deprecated, use src instead.
requirements_txt: result of "compiling" the requirements.in file.
requirements_linux: File of linux specific resolve output to check validate if requirement.in has changes.
requirements_darwin: File of darwin specific resolve output to check validate if requirement.in has changes.
@@ -62,7 +68,11 @@ def compile_pip_requirements(
visibility: passed to both the _test and .update rules.
**kwargs: other bazel attributes passed to the "_test" rule.
"""
- requirements_in = name + ".in" if requirements_in == None else requirements_in
+ if requirements_in and src:
+ fail("Only one of 'src' and 'requirements_in' attributes can be used")
+ else:
+ src = requirements_in or src or "pyproject.toml"
+
requirements_txt = name + ".txt" if requirements_txt == None else requirements_txt
# "Default" target produced by this macro
@@ -74,7 +84,7 @@ def compile_pip_requirements(
visibility = visibility,
)
- data = [name, requirements_in, requirements_txt] + [f for f in (requirements_linux, requirements_darwin, requirements_windows) if f != None]
+ data = [name, requirements_txt, src] + [f for f in (requirements_linux, requirements_darwin, requirements_windows) if f != None]
# Use the Label constructor so this is expanded in the context of the file
# where it appears, which is to say, in @rules_python
@@ -83,27 +93,36 @@ def compile_pip_requirements(
loc = "$(rlocationpath {})"
args = [
- loc.format(requirements_in),
+ loc.format(src),
loc.format(requirements_txt),
- # String None is a placeholder for argv ordering.
- loc.format(requirements_linux) if requirements_linux else "None",
- loc.format(requirements_darwin) if requirements_darwin else "None",
- loc.format(requirements_windows) if requirements_windows else "None",
"//%s:%s.update" % (native.package_name(), name),
- ] + (["--generate-hashes"] if generate_hashes else []) + extra_args
+ "--resolver=backtracking",
+ "--allow-unsafe",
+ ]
+ if generate_hashes:
+ args.append("--generate-hashes")
+ if requirements_linux:
+ args.append("--requirements-linux={}".format(loc.format(requirements_linux)))
+ if requirements_darwin:
+ args.append("--requirements-darwin={}".format(loc.format(requirements_darwin)))
+ if requirements_windows:
+ args.append("--requirements-windows={}".format(loc.format(requirements_windows)))
+ args.extend(extra_args)
deps = [
requirement("build"),
requirement("click"),
requirement("colorama"),
+ requirement("importlib_metadata"),
+ requirement("more_itertools"),
+ requirement("packaging"),
requirement("pep517"),
requirement("pip"),
requirement("pip_tools"),
+ requirement("pyproject_hooks"),
requirement("setuptools"),
requirement("tomli"),
- requirement("importlib_metadata"),
requirement("zipp"),
- requirement("more_itertools"),
Label("//python/runfiles:runfiles"),
] + extra_deps
diff --git a/python/pip_install/tools/dependency_resolver/dependency_resolver.py b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
index e277cf9..5e914bc 100644
--- a/python/pip_install/tools/dependency_resolver/dependency_resolver.py
+++ b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
@@ -19,7 +19,9 @@ import os
import shutil
import sys
from pathlib import Path
+from typing import Optional, Tuple
+import click
import piptools.writer as piptools_writer
from piptools.scripts.compile import cli
@@ -77,24 +79,25 @@ def _locate(bazel_runfiles, file):
return bazel_runfiles.Rlocation(file)
-if __name__ == "__main__":
- if len(sys.argv) < 4:
- print(
- "Expected at least two arguments: requirements_in requirements_out",
- file=sys.stderr,
- )
- sys.exit(1)
-
- parse_str_none = lambda s: None if s == "None" else s
+@click.command(context_settings={"ignore_unknown_options": True})
+@click.argument("requirements_in")
+@click.argument("requirements_txt")
+@click.argument("update_target_label")
+@click.option("--requirements-linux")
+@click.option("--requirements-darwin")
+@click.option("--requirements-windows")
+@click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
+def main(
+ requirements_in: str,
+ requirements_txt: str,
+ update_target_label: str,
+ requirements_linux: Optional[str],
+ requirements_darwin: Optional[str],
+ requirements_windows: Optional[str],
+ extra_args: Tuple[str, ...],
+) -> None:
bazel_runfiles = runfiles.Create()
- requirements_in = sys.argv.pop(1)
- requirements_txt = sys.argv.pop(1)
- requirements_linux = parse_str_none(sys.argv.pop(1))
- requirements_darwin = parse_str_none(sys.argv.pop(1))
- requirements_windows = parse_str_none(sys.argv.pop(1))
- update_target_label = sys.argv.pop(1)
-
requirements_file = _select_golden_requirements_file(
requirements_txt=requirements_txt, requirements_linux=requirements_linux,
requirements_darwin=requirements_darwin, requirements_windows=requirements_windows
@@ -128,6 +131,8 @@ if __name__ == "__main__":
os.environ["LC_ALL"] = "C.UTF-8"
os.environ["LANG"] = "C.UTF-8"
+ argv = []
+
UPDATE = True
# Detect if we are running under `bazel test`.
if "TEST_TMPDIR" in os.environ:
@@ -136,8 +141,7 @@ if __name__ == "__main__":
# to the real user cache, Bazel sandboxing makes the file read-only
# and we fail.
# In theory this makes the test more hermetic as well.
- sys.argv.append("--cache-dir")
- sys.argv.append(os.environ["TEST_TMPDIR"])
+ argv.append(f"--cache-dir={os.environ['TEST_TMPDIR']}")
# Make a copy for pip-compile to read and mutate.
requirements_out = os.path.join(
os.environ["TEST_TMPDIR"], os.path.basename(requirements_file) + ".out"
@@ -153,14 +157,13 @@ if __name__ == "__main__":
os.environ["CUSTOM_COMPILE_COMMAND"] = update_command
os.environ["PIP_CONFIG_FILE"] = os.getenv("PIP_CONFIG_FILE") or os.devnull
- sys.argv.append("--output-file")
- sys.argv.append(requirements_file_relative if UPDATE else requirements_out)
- sys.argv.append(
+ argv.append(f"--output-file={requirements_file_relative if UPDATE else requirements_out}")
+ argv.append(
requirements_in_relative
if Path(requirements_in_relative).exists()
else resolved_requirements_in
)
- print(sys.argv)
+ argv.extend(extra_args)
if UPDATE:
print("Updating " + requirements_file_relative)
@@ -176,7 +179,7 @@ if __name__ == "__main__":
resolved_requirements_file, requirements_file_tree
)
)
- cli()
+ cli(argv)
requirements_file_relative_path = Path(requirements_file_relative)
content = requirements_file_relative_path.read_text()
content = content.replace(absolute_path_prefix, "")
@@ -185,7 +188,7 @@ if __name__ == "__main__":
# cli will exit(0) on success
try:
print("Checking " + requirements_file)
- cli()
+ cli(argv)
print("cli() should exit", file=sys.stderr)
sys.exit(1)
except SystemExit as e:
@@ -219,3 +222,7 @@ if __name__ == "__main__":
file=sys.stderr,
)
sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/pip_install/tools/lib/BUILD.bazel b/python/pip_install/tools/lib/BUILD.bazel
deleted file mode 100644
index 37a8b09..0000000
--- a/python/pip_install/tools/lib/BUILD.bazel
+++ /dev/null
@@ -1,82 +0,0 @@
-load("//python:defs.bzl", "py_library", "py_test")
-load(":annotations_test_helpers.bzl", "package_annotation", "package_annotations_file")
-
-py_library(
- name = "lib",
- srcs = [
- "annotation.py",
- "arguments.py",
- "bazel.py",
- ],
- visibility = ["//python/pip_install:__subpackages__"],
-)
-
-package_annotations_file(
- name = "mock_annotations",
- annotations = {
- "pkg_a": package_annotation(),
- "pkg_b": package_annotation(
- data_exclude_glob = [
- "*.foo",
- "*.bar",
- ],
- ),
- "pkg_c": package_annotation(
- # The `join` and `strip` here accounts for potential differences
- # in new lines between unix and windows hosts.
- additive_build_content = "\n".join([line.strip() for line in """\
-cc_library(
- name = "my_target",
- hdrs = glob(["**/*.h"]),
- srcs = glob(["**/*.cc"]),
-)
-""".splitlines()]),
- data = [":my_target"],
- ),
- "pkg_d": package_annotation(
- srcs_exclude_glob = ["pkg_d/tests/**"],
- ),
- },
- tags = ["manual"],
-)
-
-py_test(
- name = "annotations_test",
- size = "small",
- srcs = ["annotations_test.py"],
- data = [":mock_annotations"],
- env = {"MOCK_ANNOTATIONS": "$(rootpath :mock_annotations)"},
- deps = [
- ":lib",
- "//python/runfiles",
- ],
-)
-
-py_test(
- name = "arguments_test",
- size = "small",
- srcs = [
- "arguments_test.py",
- ],
- deps = [
- ":lib",
- ],
-)
-
-filegroup(
- name = "distribution",
- srcs = glob(
- ["*"],
- exclude = ["*_test.py"],
- ),
- visibility = ["//python/pip_install:__subpackages__"],
-)
-
-filegroup(
- name = "py_srcs",
- srcs = glob(
- include = ["**/*.py"],
- exclude = ["**/*_test.py"],
- ),
- visibility = ["//python/pip_install:__subpackages__"],
-)
diff --git a/python/pip_install/tools/lib/annotation.py b/python/pip_install/tools/lib/annotation.py
deleted file mode 100644
index c980080..0000000
--- a/python/pip_install/tools/lib/annotation.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# 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 json
-import logging
-from collections import OrderedDict
-from pathlib import Path
-from typing import Any, Dict, List
-
-
-class Annotation(OrderedDict):
- """A python representation of `@rules_python//python:pip.bzl%package_annotation`"""
-
- def __init__(self, content: Dict[str, Any]) -> None:
-
- missing = []
- ordered_content = OrderedDict()
- for field in (
- "additive_build_content",
- "copy_executables",
- "copy_files",
- "data",
- "data_exclude_glob",
- "srcs_exclude_glob",
- ):
- if field not in content:
- missing.append(field)
- continue
- ordered_content.update({field: content.pop(field)})
-
- if missing:
- raise ValueError("Data missing from initial annotation: {}".format(missing))
-
- if content:
- raise ValueError(
- "Unexpected data passed to annotations: {}".format(
- sorted(list(content.keys()))
- )
- )
-
- return OrderedDict.__init__(self, ordered_content)
-
- @property
- def additive_build_content(self) -> str:
- return self["additive_build_content"]
-
- @property
- def copy_executables(self) -> Dict[str, str]:
- return self["copy_executables"]
-
- @property
- def copy_files(self) -> Dict[str, str]:
- return self["copy_files"]
-
- @property
- def data(self) -> List[str]:
- return self["data"]
-
- @property
- def data_exclude_glob(self) -> List[str]:
- return self["data_exclude_glob"]
-
- @property
- def srcs_exclude_glob(self) -> List[str]:
- return self["srcs_exclude_glob"]
-
-
-class AnnotationsMap:
- """A mapping of python package names to [Annotation]"""
-
- def __init__(self, json_file: Path):
- content = json.loads(json_file.read_text())
-
- self._annotations = {pkg: Annotation(data) for (pkg, data) in content.items()}
-
- @property
- def annotations(self) -> Dict[str, Annotation]:
- return self._annotations
-
- def collect(self, requirements: List[str]) -> Dict[str, Annotation]:
- unused = self.annotations
- collection = {}
- for pkg in requirements:
- if pkg in unused:
- collection.update({pkg: unused.pop(pkg)})
-
- if unused:
- logging.warning(
- "Unused annotations: {}".format(sorted(list(unused.keys())))
- )
-
- return collection
-
-
-def annotation_from_str_path(path: str) -> Annotation:
- """Load an annotation from a json encoded file
-
- Args:
- path (str): The path to a json encoded file
-
- Returns:
- Annotation: The deserialized annotations
- """
- json_file = Path(path)
- content = json.loads(json_file.read_text())
- return Annotation(content)
-
-
-def annotations_map_from_str_path(path: str) -> AnnotationsMap:
- """Load an annotations map from a json encoded file
-
- Args:
- path (str): The path to a json encoded file
-
- Returns:
- AnnotationsMap: The deserialized annotations map
- """
- return AnnotationsMap(Path(path))
diff --git a/python/pip_install/tools/lib/annotations_test.py b/python/pip_install/tools/lib/annotations_test.py
deleted file mode 100644
index f7c360f..0000000
--- a/python/pip_install/tools/lib/annotations_test.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/env python3
-# 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 textwrap
-import unittest
-from pathlib import Path
-
-from python.pip_install.tools.lib.annotation import Annotation, AnnotationsMap
-from python.runfiles import runfiles
-
-
-class AnnotationsTestCase(unittest.TestCase):
-
- maxDiff = None
-
- def test_annotations_constructor(self) -> None:
- annotations_env = os.environ.get("MOCK_ANNOTATIONS")
- self.assertIsNotNone(annotations_env)
-
- r = runfiles.Create()
-
- annotations_path = Path(r.Rlocation("rules_python/{}".format(annotations_env)))
- self.assertTrue(annotations_path.exists())
-
- annotations_map = AnnotationsMap(annotations_path)
- self.assertListEqual(
- list(annotations_map.annotations.keys()),
- ["pkg_a", "pkg_b", "pkg_c", "pkg_d"],
- )
-
- collection = annotations_map.collect(["pkg_a", "pkg_b", "pkg_c", "pkg_d"])
-
- self.assertEqual(
- collection["pkg_a"],
- Annotation(
- {
- "additive_build_content": None,
- "copy_executables": {},
- "copy_files": {},
- "data": [],
- "data_exclude_glob": [],
- "srcs_exclude_glob": [],
- }
- ),
- )
-
- self.assertEqual(
- collection["pkg_b"],
- Annotation(
- {
- "additive_build_content": None,
- "copy_executables": {},
- "copy_files": {},
- "data": [],
- "data_exclude_glob": ["*.foo", "*.bar"],
- "srcs_exclude_glob": [],
- }
- ),
- )
-
- self.assertEqual(
- collection["pkg_c"],
- Annotation(
- {
- # The `join` and `strip` here accounts for potential
- # differences in new lines between unix and windows
- # hosts.
- "additive_build_content": "\n".join(
- [
- line.strip()
- for line in textwrap.dedent(
- """\
- cc_library(
- name = "my_target",
- hdrs = glob(["**/*.h"]),
- srcs = glob(["**/*.cc"]),
- )
- """
- ).splitlines()
- ]
- ),
- "copy_executables": {},
- "copy_files": {},
- "data": [":my_target"],
- "data_exclude_glob": [],
- "srcs_exclude_glob": [],
- }
- ),
- )
-
- self.assertEqual(
- collection["pkg_d"],
- Annotation(
- {
- "additive_build_content": None,
- "copy_executables": {},
- "copy_files": {},
- "data": [],
- "data_exclude_glob": [],
- "srcs_exclude_glob": ["pkg_d/tests/**"],
- }
- ),
- )
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/pip_install/tools/lib/annotations_test_helpers.bzl b/python/pip_install/tools/lib/annotations_test_helpers.bzl
deleted file mode 100644
index 4f56bb7..0000000
--- a/python/pip_install/tools/lib/annotations_test_helpers.bzl
+++ /dev/null
@@ -1,47 +0,0 @@
-# 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.
-
-"""Helper macros and rules for testing the `annotations` module of `tools`"""
-
-load("//python:pip.bzl", _package_annotation = "package_annotation")
-
-package_annotation = _package_annotation
-
-def _package_annotations_file_impl(ctx):
- output = ctx.actions.declare_file(ctx.label.name + ".annotations.json")
-
- annotations = {package: json.decode(data) for (package, data) in ctx.attr.annotations.items()}
- ctx.actions.write(
- output = output,
- content = json.encode_indent(annotations, indent = " " * 4),
- )
-
- return DefaultInfo(
- files = depset([output]),
- runfiles = ctx.runfiles(files = [output]),
- )
-
-package_annotations_file = rule(
- implementation = _package_annotations_file_impl,
- doc = (
- "Consumes `package_annotation` definitions in the same way " +
- "`pip_repository` rules do to produce an annotations file."
- ),
- attrs = {
- "annotations": attr.string_dict(
- doc = "See `@rules_python//python:pip.bzl%package_annotation",
- mandatory = True,
- ),
- },
-)
diff --git a/python/pip_install/tools/lib/bazel.py b/python/pip_install/tools/lib/bazel.py
deleted file mode 100644
index 81119e9..0000000
--- a/python/pip_install/tools/lib/bazel.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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 re
-
-WHEEL_FILE_LABEL = "whl"
-PY_LIBRARY_LABEL = "pkg"
-DATA_LABEL = "data"
-DIST_INFO_LABEL = "dist_info"
-WHEEL_ENTRY_POINT_PREFIX = "rules_python_wheel_entry_point"
-
-
-def sanitise_name(name: str, prefix: str) -> str:
- """Sanitises the name to be compatible with Bazel labels.
-
- See the doc in ../../../private/normalize_name.bzl.
- """
- return prefix + re.sub(r"[-_.]+", "_", name).lower()
-
-
-def _whl_name_to_repo_root(whl_name: str, repo_prefix: str) -> str:
- return "@{}//".format(sanitise_name(whl_name, prefix=repo_prefix))
-
-
-def sanitised_repo_library_label(whl_name: str, repo_prefix: str) -> str:
- return '"{}:{}"'.format(
- _whl_name_to_repo_root(whl_name, repo_prefix), PY_LIBRARY_LABEL
- )
-
-
-def sanitised_repo_file_label(whl_name: str, repo_prefix: str) -> str:
- return '"{}:{}"'.format(
- _whl_name_to_repo_root(whl_name, repo_prefix), WHEEL_FILE_LABEL
- )
diff --git a/python/pip_install/tools/requirements.txt b/python/pip_install/tools/requirements.txt
new file mode 100755
index 0000000..bf9fe46
--- /dev/null
+++ b/python/pip_install/tools/requirements.txt
@@ -0,0 +1,14 @@
+build
+click
+colorama
+importlib_metadata
+installer
+more_itertools
+packaging
+pep517
+pip
+pip_tools
+setuptools
+tomli
+wheel
+zipp
diff --git a/python/pip_install/tools/wheel_installer/BUILD.bazel b/python/pip_install/tools/wheel_installer/BUILD.bazel
index 54bbc46..a396488 100644
--- a/python/pip_install/tools/wheel_installer/BUILD.bazel
+++ b/python/pip_install/tools/wheel_installer/BUILD.bazel
@@ -4,14 +4,16 @@ load("//python/pip_install:repositories.bzl", "requirement")
py_library(
name = "lib",
srcs = [
+ "arguments.py",
"namespace_pkgs.py",
"wheel.py",
"wheel_installer.py",
],
+ visibility = ["//third_party/rules_pycross/pycross/private:__subpackages__"],
deps = [
- "//python/pip_install/tools/lib",
requirement("installer"),
requirement("pip"),
+ requirement("packaging"),
requirement("setuptools"),
],
)
@@ -25,6 +27,17 @@ py_binary(
)
py_test(
+ name = "arguments_test",
+ size = "small",
+ srcs = [
+ "arguments_test.py",
+ ],
+ deps = [
+ ":lib",
+ ],
+)
+
+py_test(
name = "namespace_pkgs_test",
size = "small",
srcs = [
@@ -36,6 +49,18 @@ py_test(
)
py_test(
+ name = "wheel_test",
+ size = "small",
+ srcs = [
+ "wheel_test.py",
+ ],
+ data = ["//examples/wheel:minimal_with_py_package"],
+ deps = [
+ ":lib",
+ ],
+)
+
+py_test(
name = "wheel_installer_test",
size = "small",
srcs = [
diff --git a/python/pip_install/tools/lib/arguments.py b/python/pip_install/tools/wheel_installer/arguments.py
index 974f03c..71133c2 100644
--- a/python/pip_install/tools/lib/arguments.py
+++ b/python/pip_install/tools/wheel_installer/arguments.py
@@ -12,16 +12,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import argparse
import json
-from argparse import ArgumentParser
+import pathlib
+from typing import Any, Dict, Set
+from python.pip_install.tools.wheel_installer import wheel
-def parse_common_args(parser: ArgumentParser) -> ArgumentParser:
+
+def parser(**kwargs: Any) -> argparse.ArgumentParser:
+ """Create a parser for the wheel_installer tool."""
+ parser = argparse.ArgumentParser(
+ **kwargs,
+ )
parser.add_argument(
- "--repo",
+ "--requirement",
action="store",
required=True,
- help="The external repo name to install dependencies. In the format '@{REPO_NAME}'",
+ help="A single PEP508 requirement specifier string.",
)
parser.add_argument(
"--isolated",
@@ -34,6 +42,12 @@ def parse_common_args(parser: ArgumentParser) -> ArgumentParser:
help="Extra arguments to pass down to pip.",
)
parser.add_argument(
+ "--platform",
+ action="extend",
+ type=wheel.Platform.from_string,
+ help="Platforms to target dependencies. Can be used multiple times.",
+ )
+ parser.add_argument(
"--pip_data_exclude",
action="store",
help="Additional data exclusion parameters to add to the pip packages BUILD file.",
@@ -49,21 +63,22 @@ def parse_common_args(parser: ArgumentParser) -> ArgumentParser:
help="Extra environment variables to set on the pip environment.",
)
parser.add_argument(
- "--repo-prefix",
- required=True,
- help="Prefix to prepend to packages",
- )
- parser.add_argument(
"--download_only",
action="store_true",
help="Use 'pip download' instead of 'pip wheel'. Disables building wheels from source, but allows use of "
"--platform, --python-version, --implementation, and --abi in --extra_pip_args.",
)
+ parser.add_argument(
+ "--whl-file",
+ type=pathlib.Path,
+ help="Extract a whl file to be used within Bazel.",
+ )
return parser
-def deserialize_structured_args(args):
+def deserialize_structured_args(args: Dict[str, str]) -> Dict:
"""Deserialize structured arguments passed from the starlark rules.
+
Args:
args: dict of parsed command line arguments
"""
@@ -74,3 +89,18 @@ def deserialize_structured_args(args):
else:
args[arg_name] = []
return args
+
+
+def get_platforms(args: argparse.Namespace) -> Set:
+ """Aggregate platforms into a single set.
+
+ Args:
+ args: dict of parsed command line arguments
+ """
+ platforms = set()
+ if args.platform is None:
+ return platforms
+
+ platforms.update(args.platform)
+
+ return platforms
diff --git a/python/pip_install/tools/lib/arguments_test.py b/python/pip_install/tools/wheel_installer/arguments_test.py
index dfa96a8..840c2fa 100644
--- a/python/pip_install/tools/lib/arguments_test.py
+++ b/python/pip_install/tools/wheel_installer/arguments_test.py
@@ -16,35 +16,30 @@ import argparse
import json
import unittest
-from python.pip_install.tools.lib import arguments
+from python.pip_install.tools.wheel_installer import arguments, wheel
class ArgumentsTestCase(unittest.TestCase):
def test_arguments(self) -> None:
- parser = argparse.ArgumentParser()
- parser = arguments.parse_common_args(parser)
+ parser = arguments.parser()
repo_name = "foo"
repo_prefix = "pypi_"
index_url = "--index_url=pypi.org/simple"
extra_pip_args = [index_url]
+ requirement = "foo==1.0.0 --hash=sha256:deadbeef"
args_dict = vars(
parser.parse_args(
args=[
- "--repo",
- repo_name,
+ f'--requirement="{requirement}"',
f"--extra_pip_args={json.dumps({'arg': extra_pip_args})}",
- "--repo-prefix",
- repo_prefix,
]
)
)
args_dict = arguments.deserialize_structured_args(args_dict)
- self.assertIn("repo", args_dict)
+ self.assertIn("requirement", args_dict)
self.assertIn("extra_pip_args", args_dict)
self.assertEqual(args_dict["pip_data_exclude"], [])
self.assertEqual(args_dict["enable_implicit_namespace_pkgs"], False)
- self.assertEqual(args_dict["repo"], repo_name)
- self.assertEqual(args_dict["repo_prefix"], repo_prefix)
self.assertEqual(args_dict["extra_pip_args"], extra_pip_args)
def test_deserialize_structured_args(self) -> None:
@@ -57,6 +52,18 @@ class ArgumentsTestCase(unittest.TestCase):
self.assertEqual(args["environment"], {"PIP_DO_SOMETHING": "True"})
self.assertEqual(args["extra_pip_args"], [])
+ def test_platform_aggregation(self) -> None:
+ parser = arguments.parser()
+ args = parser.parse_args(
+ args=[
+ "--platform=host",
+ "--platform=linux_*",
+ "--platform=all",
+ "--requirement=foo",
+ ]
+ )
+ self.assertEqual(set(wheel.Platform.all()), arguments.get_platforms(args))
+
if __name__ == "__main__":
unittest.main()
diff --git a/python/pip_install/tools/wheel_installer/wheel.py b/python/pip_install/tools/wheel_installer/wheel.py
index 84af04c..efd916d 100644
--- a/python/pip_install/tools/wheel_installer/wheel.py
+++ b/python/pip_install/tools/wheel_installer/wheel.py
@@ -13,18 +13,372 @@
# limitations under the License.
"""Utility class to inspect an extracted wheel directory"""
+
import email
-from typing import Dict, Optional, Set, Tuple
+import platform
+import re
+import sys
+from collections import defaultdict
+from dataclasses import dataclass
+from enum import Enum
+from pathlib import Path
+from typing import Any, Dict, List, Optional, Set, Tuple, Union
import installer
-import pkg_resources
+from packaging.requirements import Requirement
from pip._vendor.packaging.utils import canonicalize_name
+class OS(Enum):
+ linux = 1
+ osx = 2
+ windows = 3
+ darwin = osx
+ win32 = windows
+
+
+class Arch(Enum):
+ x86_64 = 1
+ x86_32 = 2
+ aarch64 = 3
+ ppc = 4
+ s390x = 5
+ amd64 = x86_64
+ arm64 = aarch64
+ i386 = x86_32
+ i686 = x86_32
+ x86 = x86_32
+ ppc64le = ppc
+
+
+@dataclass(frozen=True)
+class Platform:
+ os: OS
+ arch: Optional[Arch] = None
+
+ @classmethod
+ def all(cls, want_os: Optional[OS] = None) -> List["Platform"]:
+ return sorted(
+ [
+ cls(os=os, arch=arch)
+ for os in OS
+ for arch in Arch
+ if not want_os or want_os == os
+ ]
+ )
+
+ @classmethod
+ def host(cls) -> List["Platform"]:
+ """Use the Python interpreter to detect the platform.
+
+ We extract `os` from sys.platform and `arch` from platform.machine
+
+ Returns:
+ A list of parsed values which makes the signature the same as
+ `Platform.all` and `Platform.from_string`.
+ """
+ return [
+ cls(
+ os=OS[sys.platform.lower()],
+ # FIXME @aignas 2023-12-13: Hermetic toolchain on Windows 3.11.6
+ # is returning an empty string here, so lets default to x86_64
+ arch=Arch[platform.machine().lower() or "x86_64"],
+ )
+ ]
+
+ def __lt__(self, other: Any) -> bool:
+ """Add a comparison method, so that `sorted` returns the most specialized platforms first."""
+ if not isinstance(other, Platform) or other is None:
+ raise ValueError(f"cannot compare {other} with Platform")
+
+ if self.arch is None and other.arch is not None:
+ return True
+
+ if self.arch is not None and other.arch is None:
+ return True
+
+ # Here we ensure that we sort by OS before sorting by arch
+
+ if self.arch is None and other.arch is None:
+ return self.os.value < other.os.value
+
+ if self.os.value < other.os.value:
+ return True
+
+ if self.os.value == other.os.value:
+ return self.arch.value < other.arch.value
+
+ return False
+
+ def __str__(self) -> str:
+ if self.arch is None:
+ return f"@platforms//os:{self.os.name.lower()}"
+
+ return self.os.name.lower() + "_" + self.arch.name.lower()
+
+ @classmethod
+ def from_string(cls, platform: Union[str, List[str]]) -> List["Platform"]:
+ """Parse a string and return a list of platforms"""
+ platform = [platform] if isinstance(platform, str) else list(platform)
+ ret = set()
+ for p in platform:
+ if p == "host":
+ ret.update(cls.host())
+ elif p == "all":
+ ret.update(cls.all())
+ elif p.endswith("*"):
+ os, _, _ = p.partition("_")
+ ret.update(cls.all(OS[os]))
+ else:
+ os, _, arch = p.partition("_")
+ ret.add(cls(os=OS[os], arch=Arch[arch]))
+
+ return sorted(ret)
+
+ # NOTE @aignas 2023-12-05: below is the minimum number of accessors that are defined in
+ # https://peps.python.org/pep-0496/ to make rules_python generate dependencies.
+ #
+ # WARNING: It may not work in cases where the python implementation is different between
+ # different platforms.
+
+ # derived from OS
+ @property
+ def os_name(self) -> str:
+ if self.os == OS.linux or self.os == OS.osx:
+ return "posix"
+ elif self.os == OS.windows:
+ return "nt"
+ else:
+ return ""
+
+ @property
+ def sys_platform(self) -> str:
+ if self.os == OS.linux:
+ return "linux"
+ elif self.os == OS.osx:
+ return "darwin"
+ elif self.os == OS.windows:
+ return "win32"
+ else:
+ return ""
+
+ @property
+ def platform_system(self) -> str:
+ if self.os == OS.linux:
+ return "Linux"
+ elif self.os == OS.osx:
+ return "Darwin"
+ elif self.os == OS.windows:
+ return "Windows"
+
+ # derived from OS and Arch
+ @property
+ def platform_machine(self) -> str:
+ """Guess the target 'platform_machine' marker.
+
+ NOTE @aignas 2023-12-05: this may not work on really new systems, like
+ Windows if they define the platform markers in a different way.
+ """
+ if self.arch == Arch.x86_64:
+ return "x86_64"
+ elif self.arch == Arch.x86_32 and self.os != OS.osx:
+ return "i386"
+ elif self.arch == Arch.x86_32:
+ return ""
+ elif self.arch == Arch.aarch64 and self.os == OS.linux:
+ return "aarch64"
+ elif self.arch == Arch.aarch64:
+ # Assuming that OSX and Windows use this one since the precedent is set here:
+ # https://github.com/cgohlke/win_arm64-wheels
+ return "arm64"
+ elif self.os != OS.linux:
+ return ""
+ elif self.arch == Arch.ppc64le:
+ return "ppc64le"
+ elif self.arch == Arch.s390x:
+ return "s390x"
+ else:
+ return ""
+
+ def env_markers(self, extra: str) -> Dict[str, str]:
+ return {
+ "extra": extra,
+ "os_name": self.os_name,
+ "sys_platform": self.sys_platform,
+ "platform_machine": self.platform_machine,
+ "platform_system": self.platform_system,
+ "platform_release": "", # unset
+ "platform_version": "", # unset
+ # we assume that the following are the same as the interpreter used to setup the deps:
+ # "implementation_version": "X.Y.Z",
+ # "implementation_name": "cpython"
+ # "python_version": "X.Y",
+ # "python_full_version": "X.Y.Z",
+ # "platform_python_implementation: "CPython",
+ }
+
+
+@dataclass(frozen=True)
+class FrozenDeps:
+ deps: List[str]
+ deps_select: Dict[str, List[str]]
+
+
+class Deps:
+ def __init__(
+ self,
+ name: str,
+ extras: Optional[Set[str]] = None,
+ platforms: Optional[Set[Platform]] = None,
+ ):
+ self.name: str = Deps._normalize(name)
+ self._deps: Set[str] = set()
+ self._select: Dict[Platform, Set[str]] = defaultdict(set)
+ self._want_extras: Set[str] = extras or {""} # empty strings means no extras
+ self._platforms: Set[Platform] = platforms or set()
+
+ def _add(self, dep: str, platform: Optional[Platform]):
+ dep = Deps._normalize(dep)
+
+ # Packages may create dependency cycles when specifying optional-dependencies / 'extras'.
+ # Example: github.com/google/etils/blob/a0b71032095db14acf6b33516bca6d885fe09e35/pyproject.toml#L32.
+ if dep == self.name:
+ return
+
+ if platform:
+ self._select[platform].add(dep)
+ else:
+ self._deps.add(dep)
+
+ @staticmethod
+ def _normalize(name: str) -> str:
+ return re.sub(r"[-_.]+", "_", name).lower()
+
+ def add(self, *wheel_reqs: str) -> None:
+ reqs = [Requirement(wheel_req) for wheel_req in wheel_reqs]
+
+ # Resolve any extra extras due to self-edges
+ self._want_extras = self._resolve_extras(reqs)
+
+ # process self-edges first to resolve the extras used
+ for req in reqs:
+ self._add_req(req)
+
+ def _resolve_extras(self, reqs: List[Requirement]) -> Set[str]:
+ """Resolve extras which are due to depending on self[some_other_extra].
+
+ Some packages may have cyclic dependencies resulting from extras being used, one example is
+ `elint`, where we have one set of extras as aliases for other extras
+ and we have an extra called 'all' that includes all other extras.
+
+ When the `requirements.txt` is generated by `pip-tools`, then it is likely that
+ this step is not needed, but for other `requirements.txt` files this may be useful.
+
+ NOTE @aignas 2023-12-08: the extra resolution is not platform dependent, but
+ in order for it to become platform dependent we would have to have separate targets for each extra in
+ self._want_extras.
+ """
+ extras = self._want_extras
+
+ self_reqs = []
+ for req in reqs:
+ if Deps._normalize(req.name) != self.name:
+ continue
+
+ if req.marker is None:
+ # I am pretty sure we cannot reach this code as it does not
+ # make sense to specify packages in this way, but since it is
+ # easy to handle, lets do it.
+ #
+ # TODO @aignas 2023-12-08: add a test
+ extras = extras | req.extras
+ else:
+ # process these in a separate loop
+ self_reqs.append(req)
+
+ # A double loop is not strictly optimal, but always correct without recursion
+ for req in self_reqs:
+ if any(req.marker.evaluate({"extra": extra}) for extra in extras):
+ extras = extras | req.extras
+ else:
+ continue
+
+ # Iterate through all packages to ensure that we include all of the extras from previously
+ # visited packages.
+ for req_ in self_reqs:
+ if any(req_.marker.evaluate({"extra": extra}) for extra in extras):
+ extras = extras | req_.extras
+
+ return extras
+
+ def _add_req(self, req: Requirement) -> None:
+ extras = self._want_extras
+
+ if req.marker is None:
+ self._add(req.name, None)
+ return
+
+ marker_str = str(req.marker)
+
+ # NOTE @aignas 2023-12-08: in order to have reasonable select statements
+ # we do have to have some parsing of the markers, so it begs the question
+ # if packaging should be reimplemented in Starlark to have the best solution
+ # for now we will implement it in Python and see what the best parsing result
+ # can be before making this decision.
+ if not self._platforms or not any(
+ tag in marker_str
+ for tag in [
+ "os_name",
+ "sys_platform",
+ "platform_machine",
+ "platform_system",
+ ]
+ ):
+ if any(req.marker.evaluate({"extra": extra}) for extra in extras):
+ self._add(req.name, None)
+ return
+
+ for plat in self._platforms:
+ if not any(
+ req.marker.evaluate(plat.env_markers(extra)) for extra in extras
+ ):
+ continue
+
+ if "platform_machine" in marker_str:
+ self._add(req.name, plat)
+ else:
+ self._add(req.name, Platform(plat.os))
+
+ def build(self) -> FrozenDeps:
+ if not self._select:
+ return FrozenDeps(
+ deps=sorted(self._deps),
+ deps_select={},
+ )
+
+ # Get all of the OS-specific dependencies applicable to all architectures
+ select = {
+ p: deps for p, deps in self._select.items() if deps and p.arch is None
+ }
+ # Now add them to all arch specific dependencies
+ select.update(
+ {
+ p: deps | select.get(Platform(p.os), set())
+ for p, deps in self._select.items()
+ if deps and p.arch is not None
+ }
+ )
+
+ return FrozenDeps(
+ deps=sorted(self._deps),
+ deps_select={str(p): sorted(deps) for p, deps in sorted(select.items())},
+ )
+
+
class Wheel:
"""Representation of the compressed .whl file"""
- def __init__(self, path: str):
+ def __init__(self, path: Path):
self._path = path
@property
@@ -70,19 +424,20 @@ class Wheel:
return entry_points_mapping
- def dependencies(self, extras_requested: Optional[Set[str]] = None) -> Set[str]:
- dependency_set = set()
-
+ def dependencies(
+ self,
+ extras_requested: Set[str] = None,
+ platforms: Optional[Set[Platform]] = None,
+ ) -> FrozenDeps:
+ dependency_set = Deps(
+ self.name,
+ extras=extras_requested,
+ platforms=platforms,
+ )
for wheel_req in self.metadata.get_all("Requires-Dist", []):
- req = pkg_resources.Requirement(wheel_req) # type: ignore
-
- if req.marker is None or any(
- req.marker.evaluate({"extra": extra})
- for extra in extras_requested or [""]
- ):
- dependency_set.add(req.name) # type: ignore
+ dependency_set.add(wheel_req)
- return dependency_set
+ return dependency_set.build()
def unzip(self, directory: str) -> None:
installation_schemes = {
diff --git a/python/pip_install/tools/wheel_installer/wheel_installer.py b/python/pip_install/tools/wheel_installer/wheel_installer.py
index 9b363c3..801ef95 100644
--- a/python/pip_install/tools/wheel_installer/wheel_installer.py
+++ b/python/pip_install/tools/wheel_installer/wheel_installer.py
@@ -12,24 +12,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import argparse
+"""Build and/or fetch a single wheel based on the requirement passed in"""
+
import errno
import glob
import json
import os
import re
-import shutil
import subprocess
import sys
-import textwrap
from pathlib import Path
from tempfile import NamedTemporaryFile
-from typing import Dict, Iterable, List, Optional, Set, Tuple
+from typing import Dict, List, Optional, Set, Tuple
from pip._vendor.packaging.utils import canonicalize_name
-from python.pip_install.tools.lib import annotation, arguments, bazel
-from python.pip_install.tools.wheel_installer import namespace_pkgs, wheel
+from python.pip_install.tools.wheel_installer import arguments, namespace_pkgs, wheel
def _configure_reproducible_wheels() -> None:
@@ -103,201 +101,12 @@ def _setup_namespace_pkg_compatibility(wheel_dir: str) -> None:
namespace_pkgs.add_pkgutil_style_namespace_pkg_init(ns_pkg_dir)
-def _generate_entry_point_contents(
- module: str, attribute: str, shebang: str = "#!/usr/bin/env python3"
-) -> str:
- """Generate the contents of an entry point script.
-
- Args:
- module (str): The name of the module to use.
- attribute (str): The name of the attribute to call.
- shebang (str, optional): The shebang to use for the entry point python
- file.
-
- Returns:
- str: A string of python code.
- """
- return textwrap.dedent(
- """\
- {shebang}
- import sys
- from {module} import {attribute}
- if __name__ == "__main__":
- sys.exit({attribute}())
- """.format(
- shebang=shebang, module=module, attribute=attribute
- )
- )
-
-
-def _generate_entry_point_rule(name: str, script: str, pkg: str) -> str:
- """Generate a Bazel `py_binary` rule for an entry point script.
-
- Note that the script is used to determine the name of the target. The name of
- entry point targets should be uniuqe to avoid conflicts with existing sources or
- directories within a wheel.
-
- Args:
- name (str): The name of the generated py_binary.
- script (str): The path to the entry point's python file.
- pkg (str): The package owning the entry point. This is expected to
- match up with the `py_library` defined for each repository.
-
-
- Returns:
- str: A `py_binary` instantiation.
- """
- return textwrap.dedent(
- """\
- py_binary(
- name = "{name}",
- srcs = ["{src}"],
- # This makes this directory a top-level in the python import
- # search path for anything that depends on this.
- imports = ["."],
- deps = ["{pkg}"],
- )
- """.format(
- name=name, src=str(script).replace("\\", "/"), pkg=pkg
- )
- )
-
-
-def _generate_copy_commands(src, dest, is_executable=False) -> str:
- """Generate a [@bazel_skylib//rules:copy_file.bzl%copy_file][cf] target
-
- [cf]: https://github.com/bazelbuild/bazel-skylib/blob/1.1.1/docs/copy_file_doc.md
-
- Args:
- src (str): The label for the `src` attribute of [copy_file][cf]
- dest (str): The label for the `out` attribute of [copy_file][cf]
- is_executable (bool, optional): Whether or not the file being copied is executable.
- sets `is_executable` for [copy_file][cf]
-
- Returns:
- str: A `copy_file` instantiation.
- """
- return textwrap.dedent(
- """\
- copy_file(
- name = "{dest}.copy",
- src = "{src}",
- out = "{dest}",
- is_executable = {is_executable},
- )
- """.format(
- src=src,
- dest=dest,
- is_executable=is_executable,
- )
- )
-
-
-def _generate_build_file_contents(
- name: str,
- dependencies: List[str],
- whl_file_deps: List[str],
- data_exclude: List[str],
- tags: List[str],
- srcs_exclude: List[str] = [],
- data: List[str] = [],
- additional_content: List[str] = [],
-) -> str:
- """Generate a BUILD file for an unzipped Wheel
-
- Args:
- name: the target name of the py_library
- dependencies: a list of Bazel labels pointing to dependencies of the library
- whl_file_deps: a list of Bazel labels pointing to wheel file dependencies of this wheel.
- data_exclude: more patterns to exclude from the data attribute of generated py_library rules.
- tags: list of tags to apply to generated py_library rules.
- additional_content: A list of additional content to append to the BUILD file.
-
- Returns:
- A complete BUILD file as a string
-
- We allow for empty Python sources as for Wheels containing only compiled C code
- there may be no Python sources whatsoever (e.g. packages written in Cython: like `pymssql`).
- """
-
- data_exclude = list(
- set(
- [
- "**/* *",
- "**/*.py",
- "**/*.pyc",
- "**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNNN are created
- # RECORD is known to contain sha256 checksums of files which might include the checksums
- # of generated files produced when wheels are installed. The file is ignored to avoid
- # Bazel caching issues.
- "**/*.dist-info/RECORD",
- ]
- + data_exclude
- )
- )
-
- return "\n".join(
- [
- textwrap.dedent(
- """\
- load("@rules_python//python:defs.bzl", "py_library", "py_binary")
- load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
-
- package(default_visibility = ["//visibility:public"])
-
- filegroup(
- name = "{dist_info_label}",
- srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
- )
-
- filegroup(
- name = "{data_label}",
- srcs = glob(["data/**"], allow_empty = True),
- )
-
- filegroup(
- name = "{whl_file_label}",
- srcs = glob(["*.whl"], allow_empty = True),
- data = [{whl_file_deps}],
- )
-
- py_library(
- name = "{name}",
- srcs = glob(["site-packages/**/*.py"], exclude={srcs_exclude}, allow_empty = True),
- data = {data} + glob(["site-packages/**/*"], exclude={data_exclude}),
- # This makes this directory a top-level in the python import
- # search path for anything that depends on this.
- imports = ["site-packages"],
- deps = [{dependencies}],
- tags = [{tags}],
- )
- """.format(
- name=name,
- dependencies=",".join(sorted(dependencies)),
- data_exclude=json.dumps(sorted(data_exclude)),
- whl_file_label=bazel.WHEEL_FILE_LABEL,
- whl_file_deps=",".join(sorted(whl_file_deps)),
- tags=",".join(sorted(['"%s"' % t for t in tags])),
- data_label=bazel.DATA_LABEL,
- dist_info_label=bazel.DIST_INFO_LABEL,
- entry_point_prefix=bazel.WHEEL_ENTRY_POINT_PREFIX,
- srcs_exclude=json.dumps(sorted(srcs_exclude)),
- data=json.dumps(sorted(data)),
- )
- )
- ]
- + additional_content
- )
-
-
def _extract_wheel(
wheel_file: str,
extras: Dict[str, Set[str]],
- pip_data_exclude: List[str],
enable_implicit_namespace_pkgs: bool,
- repo_prefix: str,
+ platforms: List[wheel.Platform],
installation_dir: Path = Path("."),
- annotation: Optional[annotation.Annotation] = None,
) -> None:
"""Extracts wheel into given directory and creates py_library and filegroup targets.
@@ -305,9 +114,7 @@ def _extract_wheel(
wheel_file: the filepath of the .whl
installation_dir: the destination directory for installation of the wheel.
extras: a list of extras to add as dependencies for the installed wheel
- pip_data_exclude: list of file patterns to exclude from the generated data section of the py_library
enable_implicit_namespace_pkgs: if true, disables conversion of implicit namespace packages and will unzip as-is
- annotation: An optional set of annotations to apply to the BUILD contents of the wheel.
"""
whl = wheel.Wheel(wheel_file)
@@ -317,93 +124,47 @@ def _extract_wheel(
_setup_namespace_pkg_compatibility(installation_dir)
extras_requested = extras[whl.name] if whl.name in extras else set()
- # Packages may create dependency cycles when specifying optional-dependencies / 'extras'.
- # Example: github.com/google/etils/blob/a0b71032095db14acf6b33516bca6d885fe09e35/pyproject.toml#L32.
- self_edge_dep = set([whl.name])
- whl_deps = sorted(whl.dependencies(extras_requested) - self_edge_dep)
-
- sanitised_dependencies = [
- bazel.sanitised_repo_library_label(d, repo_prefix=repo_prefix) for d in whl_deps
- ]
- sanitised_wheel_file_dependencies = [
- bazel.sanitised_repo_file_label(d, repo_prefix=repo_prefix) for d in whl_deps
- ]
-
- entry_points = []
- for name, (module, attribute) in sorted(whl.entry_points().items()):
- # There is an extreme edge-case with entry_points that end with `.py`
- # See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174
- entry_point_without_py = f"{name[:-3]}_py" if name.endswith(".py") else name
- entry_point_target_name = (
- f"{bazel.WHEEL_ENTRY_POINT_PREFIX}_{entry_point_without_py}"
- )
- entry_point_script_name = f"{entry_point_target_name}.py"
- (installation_dir / entry_point_script_name).write_text(
- _generate_entry_point_contents(module, attribute)
- )
- entry_points.append(
- _generate_entry_point_rule(
- entry_point_target_name,
- entry_point_script_name,
- bazel.PY_LIBRARY_LABEL,
- )
- )
- with open(os.path.join(installation_dir, "BUILD.bazel"), "w") as build_file:
- additional_content = entry_points
- data = []
- data_exclude = pip_data_exclude
- srcs_exclude = []
- if annotation:
- for src, dest in annotation.copy_files.items():
- data.append(dest)
- additional_content.append(_generate_copy_commands(src, dest))
- for src, dest in annotation.copy_executables.items():
- data.append(dest)
- additional_content.append(
- _generate_copy_commands(src, dest, is_executable=True)
- )
- data.extend(annotation.data)
- data_exclude.extend(annotation.data_exclude_glob)
- srcs_exclude.extend(annotation.srcs_exclude_glob)
- if annotation.additive_build_content:
- additional_content.append(annotation.additive_build_content)
-
- contents = _generate_build_file_contents(
- name=bazel.PY_LIBRARY_LABEL,
- dependencies=sanitised_dependencies,
- whl_file_deps=sanitised_wheel_file_dependencies,
- data_exclude=data_exclude,
- data=data,
- srcs_exclude=srcs_exclude,
- tags=["pypi_name=" + whl.name, "pypi_version=" + whl.version],
- additional_content=additional_content,
- )
- build_file.write(contents)
+ dependencies = whl.dependencies(extras_requested, platforms)
+
+ with open(os.path.join(installation_dir, "metadata.json"), "w") as f:
+ metadata = {
+ "name": whl.name,
+ "version": whl.version,
+ "deps": dependencies.deps,
+ "deps_by_platform": dependencies.deps_select,
+ "entry_points": [
+ {
+ "name": name,
+ "module": module,
+ "attribute": attribute,
+ }
+ for name, (module, attribute) in sorted(whl.entry_points().items())
+ ],
+ }
+ json.dump(metadata, f)
def main() -> None:
- parser = argparse.ArgumentParser(
- description="Build and/or fetch a single wheel based on the requirement passed in"
- )
- parser.add_argument(
- "--requirement",
- action="store",
- required=True,
- help="A single PEP508 requirement specifier string.",
- )
- parser.add_argument(
- "--annotation",
- type=annotation.annotation_from_str_path,
- help="A json encoded file containing annotations for rendered packages.",
- )
- arguments.parse_common_args(parser)
- args = parser.parse_args()
+ args = arguments.parser(description=__doc__).parse_args()
deserialized_args = dict(vars(args))
arguments.deserialize_structured_args(deserialized_args)
_configure_reproducible_wheels()
+ if args.whl_file:
+ whl = Path(args.whl_file)
+
+ name, extras_for_pkg = _parse_requirement_for_extra(args.requirement)
+ extras = {name: extras_for_pkg} if extras_for_pkg and name else dict()
+ _extract_wheel(
+ wheel_file=whl,
+ extras=extras,
+ enable_implicit_namespace_pkgs=args.enable_implicit_namespace_pkgs,
+ platforms=arguments.get_platforms(args),
+ )
+ return
+
pip_args = (
[sys.executable, "-m", "pip"]
+ (["--isolated"] if args.isolated else [])
@@ -434,18 +195,10 @@ def main() -> None:
if e.errno != errno.ENOENT:
raise
- name, extras_for_pkg = _parse_requirement_for_extra(args.requirement)
- extras = {name: extras_for_pkg} if extras_for_pkg and name else dict()
-
- whl = next(iter(glob.glob("*.whl")))
- _extract_wheel(
- wheel_file=whl,
- extras=extras,
- pip_data_exclude=deserialized_args["pip_data_exclude"],
- enable_implicit_namespace_pkgs=args.enable_implicit_namespace_pkgs,
- repo_prefix=args.repo_prefix,
- annotation=args.annotation,
- )
+ whl = Path(next(iter(glob.glob("*.whl"))))
+
+ with open("whl_file.json", "w") as f:
+ json.dump({"whl_file": f"{whl.resolve()}"}, f)
if __name__ == "__main__":
diff --git a/python/pip_install/tools/wheel_installer/wheel_installer_test.py b/python/pip_install/tools/wheel_installer/wheel_installer_test.py
index 8758b67..6eacd1f 100644
--- a/python/pip_install/tools/wheel_installer/wheel_installer_test.py
+++ b/python/pip_install/tools/wheel_installer/wheel_installer_test.py
@@ -12,13 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import json
import os
import shutil
import tempfile
import unittest
from pathlib import Path
-from python.pip_install.tools.wheel_installer import wheel_installer
+from python.pip_install.tools.wheel_installer import wheel, wheel_installer
class TestRequirementExtrasParsing(unittest.TestCase):
@@ -54,30 +55,6 @@ class TestRequirementExtrasParsing(unittest.TestCase):
)
-class BazelTestCase(unittest.TestCase):
- def test_generate_entry_point_contents(self):
- got = wheel_installer._generate_entry_point_contents("sphinx.cmd.build", "main")
- want = """#!/usr/bin/env python3
-import sys
-from sphinx.cmd.build import main
-if __name__ == "__main__":
- sys.exit(main())
-"""
- self.assertEqual(got, want)
-
- def test_generate_entry_point_contents_with_shebang(self):
- got = wheel_installer._generate_entry_point_contents(
- "sphinx.cmd.build", "main", shebang="#!/usr/bin/python"
- )
- want = """#!/usr/bin/python
-import sys
-from sphinx.cmd.build import main
-if __name__ == "__main__":
- sys.exit(main())
-"""
- self.assertEqual(got, want)
-
-
class TestWhlFilegroup(unittest.TestCase):
def setUp(self) -> None:
self.wheel_name = "example_minimal_package-0.0.1-py3-none-any.whl"
@@ -90,18 +67,61 @@ class TestWhlFilegroup(unittest.TestCase):
def test_wheel_exists(self) -> None:
wheel_installer._extract_wheel(
- self.wheel_path,
+ Path(self.wheel_path),
installation_dir=Path(self.wheel_dir),
extras={},
- pip_data_exclude=[],
enable_implicit_namespace_pkgs=False,
- repo_prefix="prefix_",
+ platforms=[],
+ )
+
+ want_files = [
+ "metadata.json",
+ "site-packages",
+ self.wheel_name,
+ ]
+ self.assertEqual(
+ sorted(want_files),
+ sorted(
+ [
+ str(p.relative_to(self.wheel_dir))
+ for p in Path(self.wheel_dir).glob("*")
+ ]
+ ),
+ )
+ with open("{}/metadata.json".format(self.wheel_dir)) as metadata_file:
+ metadata_file_content = json.load(metadata_file)
+
+ want = dict(
+ version="0.0.1",
+ name="example-minimal-package",
+ deps=[],
+ deps_by_platform={},
+ entry_points=[],
+ )
+ self.assertEqual(want, metadata_file_content)
+
+
+class TestWheelPlatform(unittest.TestCase):
+ def test_wheel_os_alias(self):
+ self.assertEqual("OS.osx", str(wheel.OS.osx))
+ self.assertEqual(str(wheel.OS.darwin), str(wheel.OS.osx))
+
+ def test_wheel_arch_alias(self):
+ self.assertEqual("Arch.x86_64", str(wheel.Arch.x86_64))
+ self.assertEqual(str(wheel.Arch.amd64), str(wheel.Arch.x86_64))
+
+ def test_wheel_platform_alias(self):
+ give = wheel.Platform(
+ os=wheel.OS.darwin,
+ arch=wheel.Arch.amd64,
+ )
+ alias = wheel.Platform(
+ os=wheel.OS.osx,
+ arch=wheel.Arch.x86_64,
)
- self.assertIn(self.wheel_name, os.listdir(self.wheel_dir))
- with open("{}/BUILD.bazel".format(self.wheel_dir)) as build_file:
- build_file_content = build_file.read()
- self.assertIn("filegroup", build_file_content)
+ self.assertEqual("osx_x86_64", str(give))
+ self.assertEqual(str(alias), str(give))
if __name__ == "__main__":
diff --git a/python/pip_install/tools/wheel_installer/wheel_test.py b/python/pip_install/tools/wheel_installer/wheel_test.py
new file mode 100644
index 0000000..721b710
--- /dev/null
+++ b/python/pip_install/tools/wheel_installer/wheel_test.py
@@ -0,0 +1,220 @@
+import unittest
+
+from python.pip_install.tools.wheel_installer import wheel
+
+
+class DepsTest(unittest.TestCase):
+ def test_simple(self):
+ deps = wheel.Deps("foo")
+ deps.add("bar")
+
+ got = deps.build()
+
+ self.assertIsInstance(got, wheel.FrozenDeps)
+ self.assertEqual(["bar"], got.deps)
+ self.assertEqual({}, got.deps_select)
+
+ def test_can_add_os_specific_deps(self):
+ platforms = {
+ "linux_x86_64",
+ "osx_x86_64",
+ "windows_x86_64",
+ }
+ deps = wheel.Deps("foo", platforms=set(wheel.Platform.from_string(platforms)))
+ deps.add(
+ "bar",
+ "posix_dep; os_name=='posix'",
+ "win_dep; os_name=='nt'",
+ )
+
+ got = deps.build()
+
+ self.assertEqual(["bar"], got.deps)
+ self.assertEqual(
+ {
+ "@platforms//os:linux": ["posix_dep"],
+ "@platforms//os:osx": ["posix_dep"],
+ "@platforms//os:windows": ["win_dep"],
+ },
+ got.deps_select,
+ )
+
+ def test_can_add_platform_specific_deps(self):
+ platforms = {
+ "linux_x86_64",
+ "osx_x86_64",
+ "osx_aarch64",
+ "windows_x86_64",
+ }
+ deps = wheel.Deps("foo", platforms=set(wheel.Platform.from_string(platforms)))
+ deps.add(
+ "bar",
+ "posix_dep; os_name=='posix'",
+ "m1_dep; sys_platform=='darwin' and platform_machine=='arm64'",
+ "win_dep; os_name=='nt'",
+ )
+
+ got = deps.build()
+
+ self.assertEqual(["bar"], got.deps)
+ self.assertEqual(
+ {
+ "osx_aarch64": ["m1_dep", "posix_dep"],
+ "@platforms//os:linux": ["posix_dep"],
+ "@platforms//os:osx": ["posix_dep"],
+ "@platforms//os:windows": ["win_dep"],
+ },
+ got.deps_select,
+ )
+
+ def test_non_platform_markers_are_added_to_common_deps(self):
+ platforms = {
+ "linux_x86_64",
+ "osx_x86_64",
+ "osx_aarch64",
+ "windows_x86_64",
+ }
+ deps = wheel.Deps("foo", platforms=set(wheel.Platform.from_string(platforms)))
+ deps.add(
+ "bar",
+ "baz; implementation_name=='cpython'",
+ "m1_dep; sys_platform=='darwin' and platform_machine=='arm64'",
+ )
+
+ got = deps.build()
+
+ self.assertEqual(["bar", "baz"], got.deps)
+ self.assertEqual(
+ {
+ "osx_aarch64": ["m1_dep"],
+ },
+ got.deps_select,
+ )
+
+ def test_self_is_ignored(self):
+ deps = wheel.Deps("foo", extras={"ssl"})
+ deps.add(
+ "bar",
+ "req_dep; extra == 'requests'",
+ "foo[requests]; extra == 'ssl'",
+ "ssl_lib; extra == 'ssl'",
+ )
+
+ got = deps.build()
+
+ self.assertEqual(["bar", "req_dep", "ssl_lib"], got.deps)
+ self.assertEqual({}, got.deps_select)
+
+ def test_handle_etils(self):
+ deps = wheel.Deps("etils", extras={"all"})
+ requires = """
+etils[array-types] ; extra == "all"
+etils[eapp] ; extra == "all"
+etils[ecolab] ; extra == "all"
+etils[edc] ; extra == "all"
+etils[enp] ; extra == "all"
+etils[epath] ; extra == "all"
+etils[epath-gcs] ; extra == "all"
+etils[epath-s3] ; extra == "all"
+etils[epy] ; extra == "all"
+etils[etqdm] ; extra == "all"
+etils[etree] ; extra == "all"
+etils[etree-dm] ; extra == "all"
+etils[etree-jax] ; extra == "all"
+etils[etree-tf] ; extra == "all"
+etils[enp] ; extra == "array-types"
+pytest ; extra == "dev"
+pytest-subtests ; extra == "dev"
+pytest-xdist ; extra == "dev"
+pyink ; extra == "dev"
+pylint>=2.6.0 ; extra == "dev"
+chex ; extra == "dev"
+torch ; extra == "dev"
+optree ; extra == "dev"
+dataclass_array ; extra == "dev"
+sphinx-apitree[ext] ; extra == "docs"
+etils[dev,all] ; extra == "docs"
+absl-py ; extra == "eapp"
+simple_parsing ; extra == "eapp"
+etils[epy] ; extra == "eapp"
+jupyter ; extra == "ecolab"
+numpy ; extra == "ecolab"
+mediapy ; extra == "ecolab"
+packaging ; extra == "ecolab"
+etils[enp] ; extra == "ecolab"
+etils[epy] ; extra == "ecolab"
+etils[epy] ; extra == "edc"
+numpy ; extra == "enp"
+etils[epy] ; extra == "enp"
+fsspec ; extra == "epath"
+importlib_resources ; extra == "epath"
+typing_extensions ; extra == "epath"
+zipp ; extra == "epath"
+etils[epy] ; extra == "epath"
+gcsfs ; extra == "epath-gcs"
+etils[epath] ; extra == "epath-gcs"
+s3fs ; extra == "epath-s3"
+etils[epath] ; extra == "epath-s3"
+typing_extensions ; extra == "epy"
+absl-py ; extra == "etqdm"
+tqdm ; extra == "etqdm"
+etils[epy] ; extra == "etqdm"
+etils[array_types] ; extra == "etree"
+etils[epy] ; extra == "etree"
+etils[enp] ; extra == "etree"
+etils[etqdm] ; extra == "etree"
+dm-tree ; extra == "etree-dm"
+etils[etree] ; extra == "etree-dm"
+jax[cpu] ; extra == "etree-jax"
+etils[etree] ; extra == "etree-jax"
+tensorflow ; extra == "etree-tf"
+etils[etree] ; extra == "etree-tf"
+etils[ecolab] ; extra == "lazy-imports"
+"""
+
+ deps.add(*requires.strip().split("\n"))
+
+ got = deps.build()
+ want = [
+ "absl_py",
+ "dm_tree",
+ "fsspec",
+ "gcsfs",
+ "importlib_resources",
+ "jax",
+ "jupyter",
+ "mediapy",
+ "numpy",
+ "packaging",
+ "s3fs",
+ "simple_parsing",
+ "tensorflow",
+ "tqdm",
+ "typing_extensions",
+ "zipp",
+ ]
+
+ self.assertEqual(want, got.deps)
+ self.assertEqual({}, got.deps_select)
+
+
+class PlatformTest(unittest.TestCase):
+ def test_can_get_host(self):
+ host = wheel.Platform.host()
+ self.assertIsNotNone(host)
+ self.assertEqual(1, len(wheel.Platform.from_string("host")))
+ self.assertEqual(host, wheel.Platform.from_string("host"))
+
+ def test_can_get_all(self):
+ all_platforms = wheel.Platform.all()
+ self.assertEqual(15, len(all_platforms))
+ self.assertEqual(all_platforms, wheel.Platform.from_string("all"))
+
+ def test_can_get_all_for_os(self):
+ linuxes = wheel.Platform.all(wheel.OS.linux)
+ self.assertEqual(5, len(linuxes))
+ self.assertEqual(linuxes, wheel.Platform.from_string("linux_*"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel
index 10af17e..25937f0 100644
--- a/python/private/BUILD.bazel
+++ b/python/private/BUILD.bazel
@@ -13,17 +13,34 @@
# limitations under the License.
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//python:py_binary.bzl", "py_binary")
+load("//python:py_library.bzl", "py_library")
load("//python:versions.bzl", "print_toolchains_checksums")
load(":stamp.bzl", "stamp_build_setting")
+package(
+ default_visibility = ["//:__subpackages__"],
+)
+
licenses(["notice"])
filegroup(
name = "distribution",
- srcs = glob(["**"]) + ["//python/private/proto:distribution"],
+ srcs = glob(["**"]) + [
+ "//python/private/bzlmod:distribution",
+ "//python/private/common:distribution",
+ "//python/private/proto:distribution",
+ "//tools/build_defs/python/private:distribution",
+ ],
visibility = ["//python:__pkg__"],
)
+filegroup(
+ name = "coverage_deps",
+ srcs = ["coverage_deps.bzl"],
+ visibility = ["//tools/private/update_deps:__pkg__"],
+)
+
# Filegroup of bzl files that can be used by downstream rules for documentation generation
filegroup(
name = "bzl",
@@ -32,23 +49,60 @@ filegroup(
)
bzl_library(
- name = "reexports_bzl",
- srcs = ["reexports.bzl"],
- visibility = [
- "//docs:__pkg__",
- "//python:__pkg__",
- ],
+ name = "auth_bzl",
+ srcs = ["auth.bzl"],
deps = [":bazel_tools_bzl"],
)
bzl_library(
- name = "util_bzl",
- srcs = ["util.bzl"],
- visibility = [
- "//docs:__subpackages__",
- "//python:__subpackages__",
+ name = "autodetecting_toolchain_bzl",
+ srcs = ["autodetecting_toolchain.bzl"],
+ deps = [
+ "//python:py_runtime_bzl",
+ "//python:py_runtime_pair_bzl",
],
- deps = ["@bazel_skylib//lib:types"],
+)
+
+bzl_library(
+ name = "bzlmod_enabled_bzl",
+ srcs = ["bzlmod_enabled.bzl"],
+)
+
+bzl_library(
+ name = "coverage_deps_bzl",
+ srcs = ["coverage_deps.bzl"],
+ deps = [
+ ":bazel_tools_bzl",
+ ":version_label_bzl",
+ ],
+)
+
+bzl_library(
+ name = "full_version_bzl",
+ srcs = ["full_version.bzl"],
+ deps = ["//python:versions_bzl"],
+)
+
+bzl_library(
+ name = "internal_config_repo_bzl",
+ srcs = ["internal_config_repo.bzl"],
+ deps = [":bzlmod_enabled_bzl"],
+)
+
+bzl_library(
+ name = "normalize_name_bzl",
+ srcs = ["normalize_name.bzl"],
+)
+
+bzl_library(
+ name = "patch_whl_bzl",
+ srcs = ["patch_whl.bzl"],
+ deps = [":parse_whl_name_bzl"],
+)
+
+bzl_library(
+ name = "parse_whl_name_bzl",
+ srcs = ["parse_whl_name.bzl"],
)
bzl_library(
@@ -73,15 +127,137 @@ bzl_library(
visibility = ["//python/cc:__pkg__"],
)
+bzl_library(
+ name = "py_console_script_binary_bzl",
+ srcs = [
+ "py_console_script_binary.bzl",
+ "py_console_script_gen.bzl",
+ ],
+ visibility = ["//python/entry_points:__pkg__"],
+ deps = [
+ "//python:py_binary_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_package_bzl",
+ srcs = ["py_package.bzl"],
+ visibility = ["//:__subpackages__"],
+)
+
+bzl_library(
+ name = "py_runtime_pair_macro_bzl",
+ srcs = ["py_runtime_pair_macro.bzl"],
+ visibility = ["//:__subpackages__"],
+ deps = [":py_runtime_pair_rule_bzl"],
+)
+
+bzl_library(
+ name = "py_runtime_pair_rule_bzl",
+ srcs = ["py_runtime_pair_rule.bzl"],
+ deps = [
+ "//python:py_runtime_bzl",
+ "//python:py_runtime_info_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_wheel_bzl",
+ srcs = ["py_wheel.bzl"],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ ":py_package_bzl",
+ ":stamp_bzl",
+ ],
+)
+
+bzl_library(
+ name = "reexports_bzl",
+ srcs = ["reexports.bzl"],
+ visibility = [
+ "//:__subpackages__",
+ ],
+ deps = [":bazel_tools_bzl"],
+)
+
+bzl_library(
+ name = "register_extension_info_bzl",
+ srcs = ["register_extension_info.bzl"],
+)
+
+bzl_library(
+ name = "render_pkg_aliases_bzl",
+ srcs = ["render_pkg_aliases.bzl"],
+ deps = [
+ ":normalize_name_bzl",
+ ":text_util_bzl",
+ ":version_label_bzl",
+ ],
+)
+
+bzl_library(
+ name = "stamp_bzl",
+ srcs = ["stamp.bzl"],
+ visibility = ["//:__subpackages__"],
+)
+
+bzl_library(
+ name = "text_util_bzl",
+ srcs = ["text_util.bzl"],
+)
+
+bzl_library(
+ name = "toolchains_repo_bzl",
+ srcs = ["toolchains_repo.bzl"],
+ deps = [
+ ":which_bzl",
+ "//python:versions_bzl",
+ ],
+)
+
+bzl_library(
+ name = "util_bzl",
+ srcs = ["util.bzl"],
+ visibility = [
+ "//:__subpackages__",
+ ],
+ deps = ["@bazel_skylib//lib:types"],
+)
+
+bzl_library(
+ name = "version_label_bzl",
+ srcs = ["version_label.bzl"],
+)
+
+bzl_library(
+ name = "which_bzl",
+ srcs = ["which.bzl"],
+ visibility = [
+ "//docs:__subpackages__",
+ "//python:__subpackages__",
+ ],
+)
+
+bzl_library(
+ name = "whl_target_platforms_bzl",
+ srcs = ["whl_target_platforms.bzl"],
+ visibility = ["//:__subpackages__"],
+)
+
+bzl_library(
+ name = "labels_bzl",
+ srcs = ["labels.bzl"],
+)
+
# @bazel_tools can't define bzl_library itself, so we just put a wrapper around it.
bzl_library(
name = "bazel_tools_bzl",
srcs = [
- "@bazel_tools//tools/python:srcs_version.bzl",
- "@bazel_tools//tools/python:toolchain.bzl",
- "@bazel_tools//tools/python:utils.bzl",
+ # This set of sources is overly broad, but it's the only public
+ # target available across Bazel versions that has all the necessary
+ # sources.
+ "@bazel_tools//tools:bzl_srcs",
],
- visibility = ["//python:__pkg__"],
)
# Needed to define bzl_library targets for docgen. (We don't define the
@@ -90,17 +266,45 @@ bzl_library(
exports_files(
[
"coverage.patch",
+ "repack_whl.py",
+ "py_cc_toolchain_rule.bzl",
"py_package.bzl",
"py_wheel.bzl",
+ "py_wheel_normalize_pep440.bzl",
"reexports.bzl",
"stamp.bzl",
"util.bzl",
- "py_cc_toolchain_rule.bzl",
],
- visibility = ["//docs:__pkg__"],
+ visibility = ["//:__subpackages__"],
+)
+
+exports_files(
+ ["python_bootstrap_template.txt"],
+ # Not actually public. Only public because it's an implicit dependency of
+ # py_runtime.
+ visibility = ["//visibility:public"],
)
# Used to determine the use of `--stamp` in Starlark rules
stamp_build_setting(name = "stamp")
print_toolchains_checksums(name = "print_toolchains_checksums")
+
+# Used for py_console_script_gen rule
+py_binary(
+ name = "py_console_script_gen_py",
+ srcs = ["py_console_script_gen.py"],
+ main = "py_console_script_gen.py",
+ visibility = [
+ "//visibility:public",
+ ],
+)
+
+py_library(
+ name = "py_console_script_gen_lib",
+ srcs = ["py_console_script_gen.py"],
+ imports = ["../.."],
+ visibility = [
+ "//tests/entry_points:__pkg__",
+ ],
+)
diff --git a/python/private/auth.bzl b/python/private/auth.bzl
new file mode 100644
index 0000000..39ada37
--- /dev/null
+++ b/python/private/auth.bzl
@@ -0,0 +1,42 @@
+# 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.
+
+"""Helpers copied from http_file source to be reused here.
+
+The implementation below is copied directly from Bazel's implementation of `http_archive`.
+Accordingly, the return value of this function should be used identically as the `auth` parameter of `http_archive`.
+Reference: https://github.com/bazelbuild/bazel/blob/6.3.2/tools/build_defs/repo/http.bzl#L109
+"""
+
+# TODO @aignas 2023-12-18: use the following instead when available.
+# load("@bazel_tools//tools/build_defs/repo:utils.bzl", "get_auth")
+load("@bazel_tools//tools/build_defs/repo:utils.bzl", "read_netrc", "read_user_netrc", "use_netrc")
+
+def get_auth(rctx, urls):
+ """Utility for retrieving netrc-based authentication parameters for repository download rules used in python_repository.
+
+ Args:
+ rctx (repository_ctx): The repository rule's context object.
+ urls: A list of URLs from which assets will be downloaded.
+
+ Returns:
+ dict: A map of authentication parameters by URL.
+ """
+ if rctx.attr.netrc:
+ netrc = read_netrc(rctx, rctx.attr.netrc)
+ elif "NETRC" in rctx.os.environ:
+ netrc = read_netrc(rctx, rctx.os.environ["NETRC"])
+ else:
+ netrc = read_user_netrc(rctx)
+ return use_netrc(netrc, urls, rctx.attr.auth_patterns)
diff --git a/python/private/autodetecting_toolchain.bzl b/python/private/autodetecting_toolchain.bzl
new file mode 100644
index 0000000..3caa5aa
--- /dev/null
+++ b/python/private/autodetecting_toolchain.bzl
@@ -0,0 +1,70 @@
+# Copyright 2019 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.
+
+"""Definitions related to the Python toolchain."""
+
+load("//python:py_runtime.bzl", "py_runtime")
+load("//python:py_runtime_pair.bzl", "py_runtime_pair")
+
+def define_autodetecting_toolchain(name):
+ """Defines the autodetecting Python toolchain.
+
+ Args:
+ name: The name of the toolchain to introduce. Must have value
+ "autodetecting_toolchain". This param is present only to make the
+ BUILD file more readable.
+ """
+ if name != "autodetecting_toolchain":
+ fail("Python autodetecting toolchain must be named " +
+ "'autodetecting_toolchain'")
+
+ # buildifier: disable=native-py
+ py_runtime(
+ name = "_autodetecting_py3_runtime",
+ interpreter = ":py3wrapper.sh",
+ python_version = "PY3",
+ stub_shebang = "#!/usr/bin/env python3",
+ visibility = ["//visibility:private"],
+ )
+
+ # This is a dummy runtime whose interpreter_path triggers the native rule
+ # logic to use the legacy behavior on Windows.
+ # TODO(#7844): Remove this target.
+ # buildifier: disable=native-py
+ py_runtime(
+ name = "_magic_sentinel_runtime",
+ interpreter_path = "/_magic_pyruntime_sentinel_do_not_use",
+ python_version = "PY3",
+ visibility = ["//visibility:private"],
+ )
+
+ py_runtime_pair(
+ name = "_autodetecting_py_runtime_pair",
+ py3_runtime = select({
+ # If we're on windows, inject the sentinel to tell native rule logic
+ # that we attempted to use the autodetecting toolchain and need to
+ # switch back to legacy behavior.
+ # TODO(#7844): Remove this hack.
+ "@platforms//os:windows": ":_magic_sentinel_runtime",
+ "//conditions:default": ":_autodetecting_py3_runtime",
+ }),
+ visibility = ["//visibility:public"],
+ )
+
+ native.toolchain(
+ name = name,
+ toolchain = ":_autodetecting_py_runtime_pair",
+ toolchain_type = ":toolchain_type",
+ visibility = ["//visibility:public"],
+ )
diff --git a/python/private/autodetecting_toolchain_interpreter.sh b/python/private/autodetecting_toolchain_interpreter.sh
new file mode 100644
index 0000000..5c8a10d
--- /dev/null
+++ b/python/private/autodetecting_toolchain_interpreter.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# Don't set -e because we don't have robust trapping and printing of errors.
+set -u
+
+# We use /bin/sh rather than /bin/bash for portability. See discussion here:
+# https://groups.google.com/forum/?nomobile=true#!topic/bazel-dev/4Ql_7eDcLC0
+# We do lose the ability to set -o pipefail.
+
+FAILURE_HEADER="\
+Error occurred while attempting to use the default Python toolchain \
+(@rules_python//python:autodetecting_toolchain)."
+
+die() {
+ echo "$FAILURE_HEADER" 1>&2
+ echo "$1" 1>&2
+ exit 1
+}
+
+# We use `which` to locate the Python interpreter command on PATH. `command -v`
+# is another option, but it doesn't check whether the file it finds has the
+# executable bit.
+#
+# A tricky situation happens when this wrapper is invoked as part of running a
+# tool, e.g. passing a py_binary target to `ctx.actions.run()`. Bazel will unset
+# the PATH variable. Then the shell will see there's no PATH and initialize its
+# own, sometimes without exporting it. This causes `which` to fail and this
+# script to think there's no Python interpreter installed. To avoid this we
+# explicitly pass PATH to each `which` invocation. We can't just export PATH
+# because that would modify the environment seen by the final user Python
+# program.
+#
+# See also:
+#
+# https://github.com/bazelbuild/continuous-integration/issues/578
+# https://github.com/bazelbuild/bazel/issues/8414
+# https://github.com/bazelbuild/bazel/issues/8415
+
+# Try the "python3" command name first, then fall back on "python".
+PYTHON_BIN="$(PATH="$PATH" which python3 2> /dev/null)"
+if [ -z "${PYTHON_BIN:-}" ]; then
+ PYTHON_BIN="$(PATH="$PATH" which python 2>/dev/null)"
+fi
+if [ -z "${PYTHON_BIN:-}" ]; then
+ die "Neither 'python3' nor 'python' were found on the target \
+platform's PATH, which is:
+
+$PATH
+
+Please ensure an interpreter is available on this platform (and marked \
+executable), or else register an appropriate Python toolchain as per the \
+documentation for py_runtime_pair \
+(https://github.com/bazelbuild/rules_python/blob/master/docs/python.md#py_runtime_pair)."
+fi
+
+exec "$PYTHON_BIN" "$@"
+
diff --git a/python/private/bzlmod/BUILD.bazel b/python/private/bzlmod/BUILD.bazel
new file mode 100644
index 0000000..a312922
--- /dev/null
+++ b/python/private/bzlmod/BUILD.bazel
@@ -0,0 +1,78 @@
+# 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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
+
+package(default_visibility = ["//:__subpackages__"])
+
+licenses(["notice"])
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+ visibility = ["//python/private:__pkg__"],
+)
+
+bzl_library(
+ name = "pip_bzl",
+ srcs = ["pip.bzl"],
+ deps = [
+ ":pip_repository_bzl",
+ "//python/pip_install:pip_repository_bzl",
+ "//python/pip_install:requirements_parser_bzl",
+ "//python/private:full_version_bzl",
+ "//python/private:normalize_name_bzl",
+ "//python/private:parse_whl_name_bzl",
+ "//python/private:version_label_bzl",
+ ":bazel_features_bzl",
+ ] + [
+ "@pythons_hub//:interpreters_bzl",
+ ] if BZLMOD_ENABLED else [],
+)
+
+bzl_library(
+ name = "bazel_features_bzl",
+ srcs = ["@bazel_features//:bzl_files"] if BZLMOD_ENABLED else [],
+)
+
+bzl_library(
+ name = "pip_repository_bzl",
+ srcs = ["pip_repository.bzl"],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ "//python/private:render_pkg_aliases_bzl",
+ "//python/private:text_util_bzl",
+ ],
+)
+
+bzl_library(
+ name = "python_bzl",
+ srcs = ["python.bzl"],
+ deps = [
+ ":pythons_hub_bzl",
+ "//python:repositories_bzl",
+ "//python/private:toolchains_repo_bzl",
+ ],
+)
+
+bzl_library(
+ name = "pythons_hub_bzl",
+ srcs = ["pythons_hub.bzl"],
+ deps = [
+ "//python:versions_bzl",
+ "//python/private:full_version_bzl",
+ "//python/private:toolchains_repo_bzl",
+ ],
+)
diff --git a/python/extensions/private/internal_deps.bzl b/python/private/bzlmod/internal_deps.bzl
index 27e290c..aadf2cc 100644
--- a/python/extensions/private/internal_deps.bzl
+++ b/python/private/bzlmod/internal_deps.bzl
@@ -8,10 +8,12 @@
"Python toolchain module extension for internal rule use"
-load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies")
+load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
+load("//python/private:internal_config_repo.bzl", "internal_config_repo")
# buildifier: disable=unused-variable
def _internal_deps_impl(module_ctx):
+ internal_config_repo(name = "rules_python_internal")
pip_install_dependencies()
internal_deps = module_extension(
diff --git a/python/private/bzlmod/pip.bzl b/python/private/bzlmod/pip.bzl
new file mode 100644
index 0000000..6d45a26
--- /dev/null
+++ b/python/private/bzlmod/pip.bzl
@@ -0,0 +1,558 @@
+# 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.
+
+"pip module extension for use with bzlmod"
+
+load("@bazel_features//:features.bzl", "bazel_features")
+load("@pythons_hub//:interpreters.bzl", "DEFAULT_PYTHON_VERSION", "INTERPRETER_LABELS")
+load(
+ "//python/pip_install:pip_repository.bzl",
+ "group_library",
+ "locked_requirements_label",
+ "pip_repository_attrs",
+ "use_isolated",
+ "whl_library",
+)
+load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
+load("//python/private:full_version.bzl", "full_version")
+load("//python/private:normalize_name.bzl", "normalize_name")
+load("//python/private:parse_whl_name.bzl", "parse_whl_name")
+load("//python/private:version_label.bzl", "version_label")
+load(":pip_repository.bzl", "pip_repository")
+
+def _whl_mods_impl(mctx):
+ """Implementation of the pip.whl_mods tag class.
+
+ This creates the JSON files used to modify the creation of different wheels.
+"""
+ whl_mods_dict = {}
+ for mod in mctx.modules:
+ for whl_mod_attr in mod.tags.whl_mods:
+ if whl_mod_attr.hub_name not in whl_mods_dict.keys():
+ whl_mods_dict[whl_mod_attr.hub_name] = {whl_mod_attr.whl_name: whl_mod_attr}
+ elif whl_mod_attr.whl_name in whl_mods_dict[whl_mod_attr.hub_name].keys():
+ # We cannot have the same wheel name in the same hub, as we
+ # will create the same JSON file name.
+ fail("""\
+Found same whl_name '{}' in the same hub '{}', please use a different hub_name.""".format(
+ whl_mod_attr.whl_name,
+ whl_mod_attr.hub_name,
+ ))
+ else:
+ whl_mods_dict[whl_mod_attr.hub_name][whl_mod_attr.whl_name] = whl_mod_attr
+
+ for hub_name, whl_maps in whl_mods_dict.items():
+ whl_mods = {}
+
+ # create a struct that we can pass to the _whl_mods_repo rule
+ # to create the different JSON files.
+ for whl_name, mods in whl_maps.items():
+ build_content = mods.additive_build_content
+ if mods.additive_build_content_file != None and mods.additive_build_content != "":
+ fail("""\
+You cannot use both the additive_build_content and additive_build_content_file arguments at the same time.
+""")
+ elif mods.additive_build_content_file != None:
+ build_content = mctx.read(mods.additive_build_content_file)
+
+ whl_mods[whl_name] = json.encode(struct(
+ additive_build_content = build_content,
+ copy_files = mods.copy_files,
+ copy_executables = mods.copy_executables,
+ data = mods.data,
+ data_exclude_glob = mods.data_exclude_glob,
+ srcs_exclude_glob = mods.srcs_exclude_glob,
+ ))
+
+ _whl_mods_repo(
+ name = hub_name,
+ whl_mods = whl_mods,
+ )
+
+def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides):
+ python_interpreter_target = pip_attr.python_interpreter_target
+
+ # if we do not have the python_interpreter set in the attributes
+ # we programmatically find it.
+ hub_name = pip_attr.hub_name
+ if python_interpreter_target == None and not pip_attr.python_interpreter:
+ python_name = "python_" + version_label(pip_attr.python_version, sep = "_")
+ if python_name not in INTERPRETER_LABELS.keys():
+ fail((
+ "Unable to find interpreter for pip hub '{hub_name}' for " +
+ "python_version={version}: Make sure a corresponding " +
+ '`python.toolchain(python_version="{version}")` call exists'
+ ).format(
+ hub_name = hub_name,
+ version = pip_attr.python_version,
+ ))
+ python_interpreter_target = INTERPRETER_LABELS[python_name]
+
+ pip_name = "{}_{}".format(
+ hub_name,
+ version_label(pip_attr.python_version),
+ )
+ requrements_lock = locked_requirements_label(module_ctx, pip_attr)
+
+ # Parse the requirements file directly in starlark to get the information
+ # needed for the whl_libary declarations below.
+ requirements_lock_content = module_ctx.read(requrements_lock)
+ parse_result = parse_requirements(requirements_lock_content)
+
+ # Replicate a surprising behavior that WORKSPACE builds allowed:
+ # Defining a repo with the same name multiple times, but only the last
+ # definition is respected.
+ # The requirement lines might have duplicate names because lines for extras
+ # are returned as just the base package name. e.g., `foo[bar]` results
+ # in an entry like `("foo", "foo[bar] == 1.0 ...")`.
+ requirements = {
+ normalize_name(entry[0]): entry
+ # The WORKSPACE pip_parse sorted entries, so mimic that ordering.
+ for entry in sorted(parse_result.requirements)
+ }.values()
+
+ extra_pip_args = pip_attr.extra_pip_args + parse_result.options
+
+ if hub_name not in whl_map:
+ whl_map[hub_name] = {}
+
+ whl_modifications = {}
+ if pip_attr.whl_modifications != None:
+ for mod, whl_name in pip_attr.whl_modifications.items():
+ whl_modifications[whl_name] = mod
+
+ requirement_cycles = {
+ name: [normalize_name(whl_name) for whl_name in whls]
+ for name, whls in pip_attr.experimental_requirement_cycles.items()
+ }
+
+ whl_group_mapping = {
+ whl_name: group_name
+ for group_name, group_whls in requirement_cycles.items()
+ for whl_name in group_whls
+ }
+
+ group_repo = "%s__groups" % (pip_name,)
+ group_library(
+ name = group_repo,
+ repo_prefix = pip_name + "_",
+ groups = pip_attr.experimental_requirement_cycles,
+ )
+
+ # Create a new wheel library for each of the different whls
+ for whl_name, requirement_line in requirements:
+ # We are not using the "sanitized name" because the user
+ # would need to guess what name we modified the whl name
+ # to.
+ annotation = whl_modifications.get(whl_name)
+ whl_name = normalize_name(whl_name)
+ group_name = whl_group_mapping.get(whl_name)
+ group_deps = requirement_cycles.get(group_name, [])
+
+ whl_library(
+ name = "%s_%s" % (pip_name, whl_name),
+ requirement = requirement_line,
+ repo = pip_name,
+ repo_prefix = pip_name + "_",
+ annotation = annotation,
+ whl_patches = {
+ p: json.encode(args)
+ for p, args in whl_overrides.get(whl_name, {}).items()
+ },
+ experimental_target_platforms = pip_attr.experimental_target_platforms,
+ python_interpreter = pip_attr.python_interpreter,
+ python_interpreter_target = python_interpreter_target,
+ quiet = pip_attr.quiet,
+ timeout = pip_attr.timeout,
+ isolated = use_isolated(module_ctx, pip_attr),
+ extra_pip_args = extra_pip_args,
+ download_only = pip_attr.download_only,
+ pip_data_exclude = pip_attr.pip_data_exclude,
+ enable_implicit_namespace_pkgs = pip_attr.enable_implicit_namespace_pkgs,
+ environment = pip_attr.environment,
+ group_name = group_name,
+ group_deps = group_deps,
+ )
+
+ if whl_name not in whl_map[hub_name]:
+ whl_map[hub_name][whl_name] = {}
+
+ whl_map[hub_name][whl_name][full_version(pip_attr.python_version)] = pip_name + "_"
+
+def _pip_impl(module_ctx):
+ """Implementation of a class tag that creates the pip hub and corresponding pip spoke whl repositories.
+
+ This implementation iterates through all of the `pip.parse` calls and creates
+ different pip hub repositories based on the "hub_name". Each of the
+ pip calls create spoke repos that uses a specific Python interpreter.
+
+ In a MODULES.bazel file we have:
+
+ pip.parse(
+ hub_name = "pip",
+ python_version = 3.9,
+ requirements_lock = "//:requirements_lock_3_9.txt",
+ requirements_windows = "//:requirements_windows_3_9.txt",
+ )
+ pip.parse(
+ hub_name = "pip",
+ python_version = 3.10,
+ requirements_lock = "//:requirements_lock_3_10.txt",
+ requirements_windows = "//:requirements_windows_3_10.txt",
+ )
+
+ For instance, we have a hub with the name of "pip".
+ A repository named the following is created. It is actually called last when
+ all of the pip spokes are collected.
+
+ - @@rules_python~override~pip~pip
+
+ As shown in the example code above we have the following.
+ Two different pip.parse statements exist in MODULE.bazel provide the hub_name "pip".
+ These definitions create two different pip spoke repositories that are
+ related to the hub "pip".
+ One spoke uses Python 3.9 and the other uses Python 3.10. This code automatically
+ determines the Python version and the interpreter.
+ Both of these pip spokes contain requirements files that includes websocket
+ and its dependencies.
+
+ We also need repositories for the wheels that the different pip spokes contain.
+ For each Python version a different wheel repository is created. In our example
+ each pip spoke had a requirements file that contained websockets. We
+ then create two different wheel repositories that are named the following.
+
+ - @@rules_python~override~pip~pip_39_websockets
+ - @@rules_python~override~pip~pip_310_websockets
+
+ And if the wheel has any other dependencies subsequent wheels are created in the same fashion.
+
+ The hub repository has aliases for `pkg`, `data`, etc, which have a select that resolves to
+ a spoke repository depending on the Python version.
+
+ Also we may have more than one hub as defined in a MODULES.bazel file. So we could have multiple
+ hubs pointing to various different pip spokes.
+
+ Some other business rules notes. A hub can only have one spoke per Python version. We cannot
+ have a hub named "pip" that has two spokes that use the Python 3.9 interpreter. Second
+ we cannot have the same hub name used in sub-modules. The hub name has to be globally
+ unique.
+
+ This implementation also handles the creation of whl_modification JSON files that are used
+ during the creation of wheel libraries. These JSON files used via the annotations argument
+ when calling wheel_installer.py.
+
+ Args:
+ module_ctx: module contents
+ """
+
+ # Build all of the wheel modifications if the tag class is called.
+ _whl_mods_impl(module_ctx)
+
+ _overriden_whl_set = {}
+ whl_overrides = {}
+
+ for module in module_ctx.modules:
+ for attr in module.tags.override:
+ if not module.is_root:
+ fail("overrides are only supported in root modules")
+
+ if not attr.file.endswith(".whl"):
+ fail("Only whl overrides are supported at this time")
+
+ whl_name = normalize_name(parse_whl_name(attr.file).distribution)
+
+ if attr.file in _overriden_whl_set:
+ fail("Duplicate module overrides for '{}'".format(attr.file))
+ _overriden_whl_set[attr.file] = None
+
+ for patch in attr.patches:
+ if whl_name not in whl_overrides:
+ whl_overrides[whl_name] = {}
+
+ if patch not in whl_overrides[whl_name]:
+ whl_overrides[whl_name][patch] = struct(
+ patch_strip = attr.patch_strip,
+ whls = [],
+ )
+
+ whl_overrides[whl_name][patch].whls.append(attr.file)
+
+ # Used to track all the different pip hubs and the spoke pip Python
+ # versions.
+ pip_hub_map = {}
+
+ # Keeps track of all the hub's whl repos across the different versions.
+ # dict[hub, dict[whl, dict[version, str pip]]]
+ # Where hub, whl, and pip are the repo names
+ hub_whl_map = {}
+
+ for mod in module_ctx.modules:
+ for pip_attr in mod.tags.parse:
+ hub_name = pip_attr.hub_name
+ if hub_name not in pip_hub_map:
+ pip_hub_map[pip_attr.hub_name] = struct(
+ module_name = mod.name,
+ python_versions = [pip_attr.python_version],
+ )
+ elif pip_hub_map[hub_name].module_name != mod.name:
+ # We cannot have two hubs with the same name in different
+ # modules.
+ fail((
+ "Duplicate cross-module pip hub named '{hub}': pip hub " +
+ "names must be unique across modules. First defined " +
+ "by module '{first_module}', second attempted by " +
+ "module '{second_module}'"
+ ).format(
+ hub = hub_name,
+ first_module = pip_hub_map[hub_name].module_name,
+ second_module = mod.name,
+ ))
+
+ elif pip_attr.python_version in pip_hub_map[hub_name].python_versions:
+ fail((
+ "Duplicate pip python version '{version}' for hub " +
+ "'{hub}' in module '{module}': the Python versions " +
+ "used for a hub must be unique"
+ ).format(
+ hub = hub_name,
+ module = mod.name,
+ version = pip_attr.python_version,
+ ))
+ else:
+ pip_hub_map[pip_attr.hub_name].python_versions.append(pip_attr.python_version)
+
+ _create_whl_repos(module_ctx, pip_attr, hub_whl_map, whl_overrides)
+
+ for hub_name, whl_map in hub_whl_map.items():
+ pip_repository(
+ name = hub_name,
+ repo_name = hub_name,
+ whl_map = whl_map,
+ default_version = full_version(DEFAULT_PYTHON_VERSION),
+ )
+
+def _pip_parse_ext_attrs():
+ attrs = dict({
+ "hub_name": attr.string(
+ mandatory = True,
+ doc = """
+The name of the repo pip dependencies will be accessible from.
+
+This name must be unique between modules; unless your module is guaranteed to
+always be the root module, it's highly recommended to include your module name
+in the hub name. Repo mapping, `use_repo(..., pip="my_modules_pip_deps")`, can
+be used for shorter local names within your module.
+
+Within a module, the same `hub_name` can be specified to group different Python
+versions of pip dependencies under one repository name. This allows using a
+Python version-agnostic name when referring to pip dependencies; the
+correct version will be automatically selected.
+
+Typically, a module will only have a single hub of pip dependencies, but this
+is not required. Each hub is a separate resolution of pip dependencies. This
+means if different programs need different versions of some library, separate
+hubs can be created, and each program can use its respective hub's targets.
+Targets from different hubs should not be used together.
+""",
+ ),
+ "python_version": attr.string(
+ mandatory = True,
+ doc = """
+The Python version the dependencies are targetting, in Major.Minor format
+(e.g., "3.11"). Patch level granularity (e.g. "3.11.1") is not supported.
+If not specified, then the default Python version (as set by the root module or
+rules_python) will be used.
+
+If an interpreter isn't explicitly provided (using `python_interpreter` or
+`python_interpreter_target`), then the version specified here must have
+a corresponding `python.toolchain()` configured.
+""",
+ ),
+ "whl_modifications": attr.label_keyed_string_dict(
+ mandatory = False,
+ doc = """\
+A dict of labels to wheel names that is typically generated by the whl_modifications.
+The labels are JSON config files describing the modifications.
+""",
+ ),
+ }, **pip_repository_attrs)
+
+ # Like the pip_repository rule, we end up setting this manually so
+ # don't allow users to override it.
+ attrs.pop("repo_prefix")
+
+ # incompatible_generate_aliases is always True in bzlmod
+ attrs.pop("incompatible_generate_aliases")
+
+ return attrs
+
+def _whl_mod_attrs():
+ attrs = {
+ "additive_build_content": attr.string(
+ doc = "(str, optional): Raw text to add to the generated `BUILD` file of a package.",
+ ),
+ "additive_build_content_file": attr.label(
+ doc = """\
+(label, optional): path to a BUILD file to add to the generated
+`BUILD` file of a package. You cannot use both additive_build_content and additive_build_content_file
+arguments at the same time.""",
+ ),
+ "copy_executables": attr.string_dict(
+ doc = """\
+(dict, optional): A mapping of `src` and `out` files for
+[@bazel_skylib//rules:copy_file.bzl][cf]. Targets generated here will also be flagged as
+executable.""",
+ ),
+ "copy_files": attr.string_dict(
+ doc = """\
+(dict, optional): A mapping of `src` and `out` files for
+[@bazel_skylib//rules:copy_file.bzl][cf]""",
+ ),
+ "data": attr.string_list(
+ doc = """\
+(list, optional): A list of labels to add as `data` dependencies to
+the generated `py_library` target.""",
+ ),
+ "data_exclude_glob": attr.string_list(
+ doc = """\
+(list, optional): A list of exclude glob patterns to add as `data` to
+the generated `py_library` target.""",
+ ),
+ "hub_name": attr.string(
+ doc = """\
+Name of the whl modification, hub we use this name to set the modifications for
+pip.parse. If you have different pip hubs you can use a different name,
+otherwise it is best practice to just use one.
+
+You cannot have the same `hub_name` in different modules. You can reuse the same
+name in the same module for different wheels that you put in the same hub, but you
+cannot have a child module that uses the same `hub_name`.
+""",
+ mandatory = True,
+ ),
+ "srcs_exclude_glob": attr.string_list(
+ doc = """\
+(list, optional): A list of labels to add as `srcs` to the generated
+`py_library` target.""",
+ ),
+ "whl_name": attr.string(
+ doc = "The whl name that the modifications are used for.",
+ mandatory = True,
+ ),
+ }
+ return attrs
+
+# NOTE: the naming of 'override' is taken from the bzlmod native
+# 'archive_override', 'git_override' bzlmod functions.
+_override_tag = tag_class(
+ attrs = {
+ "file": attr.string(
+ doc = """\
+The Python distribution file name which needs to be patched. This will be
+applied to all repositories that setup this distribution via the pip.parse tag
+class.""",
+ mandatory = True,
+ ),
+ "patch_strip": attr.int(
+ default = 0,
+ doc = """\
+The number of leading path segments to be stripped from the file name in the
+patches.""",
+ ),
+ "patches": attr.label_list(
+ doc = """\
+A list of patches to apply to the repository *after* 'whl_library' is extracted
+and BUILD.bazel file is generated.""",
+ mandatory = True,
+ ),
+ },
+ doc = """\
+Apply any overrides (e.g. patches) to a given Python distribution defined by
+other tags in this extension.""",
+)
+
+def _extension_extra_args():
+ args = {}
+
+ if bazel_features.external_deps.module_extension_has_os_arch_dependent:
+ args = args | {
+ "arch_dependent": True,
+ "os_dependent": True,
+ }
+
+ return args
+
+pip = module_extension(
+ doc = """\
+This extension is used to make dependencies from pip available.
+
+pip.parse:
+To use, call `pip.parse()` and specify `hub_name` and your requirements file.
+Dependencies will be downloaded and made available in a repo named after the
+`hub_name` argument.
+
+Each `pip.parse()` call configures a particular Python version. Multiple calls
+can be made to configure different Python versions, and will be grouped by
+the `hub_name` argument. This allows the same logical name, e.g. `@pip//numpy`
+to automatically resolve to different, Python version-specific, libraries.
+
+pip.whl_mods:
+This tag class is used to help create JSON files to describe modifications to
+the BUILD files for wheels.
+""",
+ implementation = _pip_impl,
+ tag_classes = {
+ "override": _override_tag,
+ "parse": tag_class(
+ attrs = _pip_parse_ext_attrs(),
+ doc = """\
+This tag class is used to create a pip hub and all of the spokes that are part of that hub.
+This tag class reuses most of the pip attributes that are found in
+@rules_python//python/pip_install:pip_repository.bzl.
+The exceptions are it does not use the args 'repo_prefix',
+and 'incompatible_generate_aliases'. We set the repository prefix
+for the user and the alias arg is always True in bzlmod.
+""",
+ ),
+ "whl_mods": tag_class(
+ attrs = _whl_mod_attrs(),
+ doc = """\
+This tag class is used to create JSON file that are used when calling wheel_builder.py. These
+JSON files contain instructions on how to modify a wheel's project. Each of the attributes
+create different modifications based on the type of attribute. Previously to bzlmod these
+JSON files where referred to as annotations, and were renamed to whl_modifications in this
+extension.
+""",
+ ),
+ },
+ **_extension_extra_args()
+)
+
+def _whl_mods_repo_impl(rctx):
+ rctx.file("BUILD.bazel", "")
+ for whl_name, mods in rctx.attr.whl_mods.items():
+ rctx.file("{}.json".format(whl_name), mods)
+
+_whl_mods_repo = repository_rule(
+ doc = """\
+This rule creates json files based on the whl_mods attribute.
+""",
+ implementation = _whl_mods_repo_impl,
+ attrs = {
+ "whl_mods": attr.string_dict(
+ mandatory = True,
+ doc = "JSON endcoded string that is provided to wheel_builder.py",
+ ),
+ },
+)
diff --git a/python/private/bzlmod/pip_repository.bzl b/python/private/bzlmod/pip_repository.bzl
new file mode 100644
index 0000000..9e6b0f4
--- /dev/null
+++ b/python/private/bzlmod/pip_repository.bzl
@@ -0,0 +1,87 @@
+# 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.
+
+""
+
+load("//python/private:render_pkg_aliases.bzl", "render_pkg_aliases")
+load("//python/private:text_util.bzl", "render")
+
+_BUILD_FILE_CONTENTS = """\
+package(default_visibility = ["//visibility:public"])
+
+# Ensure the `requirements.bzl` source can be accessed by stardoc, since users load() from it
+exports_files(["requirements.bzl"])
+"""
+
+def _pip_repository_impl(rctx):
+ bzl_packages = rctx.attr.whl_map.keys()
+ aliases = render_pkg_aliases(
+ repo_name = rctx.attr.repo_name,
+ rules_python = rctx.attr._template.workspace_name,
+ default_version = rctx.attr.default_version,
+ whl_map = rctx.attr.whl_map,
+ )
+ for path, contents in aliases.items():
+ rctx.file(path, contents)
+
+ # 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.
+ macro_tmpl = "@@{name}//{{}}:{{}}".format(name = rctx.attr.name)
+
+ rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS)
+ rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
+ "%%ALL_DATA_REQUIREMENTS%%": render.list([
+ macro_tmpl.format(p, "data")
+ for p in bzl_packages
+ ]),
+ "%%ALL_REQUIREMENTS%%": render.list([
+ macro_tmpl.format(p, p)
+ for p in bzl_packages
+ ]),
+ "%%ALL_WHL_REQUIREMENTS_BY_PACKAGE%%": render.dict({
+ p: macro_tmpl.format(p, "whl")
+ for p in bzl_packages
+ }),
+ "%%MACRO_TMPL%%": macro_tmpl,
+ "%%NAME%%": rctx.attr.repo_name,
+ })
+
+pip_repository_attrs = {
+ "default_version": attr.string(
+ mandatory = True,
+ doc = """\
+This is the default python version in the format of X.Y.Z. This should match
+what is setup by the 'python' extension using the 'is_default = True'
+setting.""",
+ ),
+ "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.",
+ ),
+ "whl_map": attr.string_list_dict(
+ mandatory = True,
+ doc = "The wheel map where values are python versions",
+ ),
+ "_template": attr.label(
+ default = ":requirements.bzl.tmpl",
+ ),
+}
+
+pip_repository = repository_rule(
+ attrs = pip_repository_attrs,
+ doc = """A rule for bzlmod mulitple pip repository creation. PRIVATE USE ONLY.""",
+ implementation = _pip_repository_impl,
+)
diff --git a/python/private/bzlmod/python.bzl b/python/private/bzlmod/python.bzl
new file mode 100644
index 0000000..3b59d5b
--- /dev/null
+++ b/python/private/bzlmod/python.bzl
@@ -0,0 +1,282 @@
+# 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("//python:repositories.bzl", "python_register_toolchains")
+load("//python/private:toolchains_repo.bzl", "multi_toolchain_aliases")
+load(":pythons_hub.bzl", "hub_repo")
+
+# This limit can be increased essentially arbitrarily, but doing so will cause a rebuild of all
+# targets using any of these toolchains due to the changed repository name.
+_MAX_NUM_TOOLCHAINS = 9999
+_TOOLCHAIN_INDEX_PAD_LENGTH = len(str(_MAX_NUM_TOOLCHAINS))
+
+def _toolchain_prefix(index, name):
+ """Prefixes the given name with the index, padded with zeros to ensure lexicographic sorting.
+
+ Examples:
+ _toolchain_prefix( 2, "foo") == "_0002_foo_"
+ _toolchain_prefix(2000, "foo") == "_2000_foo_"
+ """
+ return "_{}_{}_".format(_left_pad_zero(index, _TOOLCHAIN_INDEX_PAD_LENGTH), name)
+
+def _left_pad_zero(index, length):
+ if index < 0:
+ fail("index must be non-negative")
+ return ("0" * length + str(index))[-length:]
+
+# Printing a warning msg not debugging, so we have to disable
+# the buildifier check.
+# buildifier: disable=print
+def _print_warn(msg):
+ print("WARNING:", msg)
+
+def _python_register_toolchains(name, toolchain_attr, module):
+ """Calls python_register_toolchains and returns a struct used to collect the toolchains.
+ """
+ python_register_toolchains(
+ name = name,
+ python_version = toolchain_attr.python_version,
+ register_coverage_tool = toolchain_attr.configure_coverage_tool,
+ ignore_root_user_error = toolchain_attr.ignore_root_user_error,
+ )
+ return struct(
+ python_version = toolchain_attr.python_version,
+ name = name,
+ module = struct(name = module.name, is_root = module.is_root),
+ )
+
+def _python_impl(module_ctx):
+ # The toolchain_info structs to register, in the order to register them in.
+ # NOTE: The last element is special: it is treated as the default toolchain,
+ # so there is special handling to ensure the last entry is the correct one.
+ toolchains = []
+
+ # We store the default toolchain separately to ensure it is the last
+ # toolchain added to toolchains.
+ # This is a toolchain_info struct.
+ default_toolchain = None
+
+ # Map of string Major.Minor to the toolchain_info struct
+ global_toolchain_versions = {}
+
+ for mod in module_ctx.modules:
+ module_toolchain_versions = []
+
+ for toolchain_attr in mod.tags.toolchain:
+ toolchain_version = toolchain_attr.python_version
+ toolchain_name = "python_" + toolchain_version.replace(".", "_")
+
+ # Duplicate versions within a module indicate a misconfigured module.
+ if toolchain_version in module_toolchain_versions:
+ _fail_duplicate_module_toolchain_version(toolchain_version, mod.name)
+ module_toolchain_versions.append(toolchain_version)
+
+ # Only the root module and rules_python are allowed to specify the default
+ # toolchain for a couple reasons:
+ # * It prevents submodules from specifying different defaults and only
+ # one of them winning.
+ # * rules_python needs to set a soft default in case the root module doesn't,
+ # e.g. if the root module doesn't use Python itself.
+ # * The root module is allowed to override the rules_python default.
+ if mod.is_root:
+ # A single toolchain is treated as the default because it's unambiguous.
+ is_default = toolchain_attr.is_default or len(mod.tags.toolchain) == 1
+ elif mod.name == "rules_python" and not default_toolchain:
+ # We don't do the len() check because we want the default that rules_python
+ # sets to be clearly visible.
+ is_default = toolchain_attr.is_default
+ else:
+ is_default = False
+
+ if is_default and default_toolchain != None:
+ _fail_multiple_default_toolchains(
+ first = default_toolchain.name,
+ second = toolchain_name,
+ )
+
+ # Ignore version collisions in the global scope because there isn't
+ # much else that can be done. Modules don't know and can't control
+ # what other modules do, so the first in the dependency graph wins.
+ if toolchain_version in global_toolchain_versions:
+ # If the python version is explicitly provided by the root
+ # module, they should not be warned for choosing the same
+ # version that rules_python provides as default.
+ first = global_toolchain_versions[toolchain_version]
+ if mod.name != "rules_python" or not first.module.is_root:
+ _warn_duplicate_global_toolchain_version(
+ toolchain_version,
+ first = first,
+ second_toolchain_name = toolchain_name,
+ second_module_name = mod.name,
+ )
+ toolchain_info = None
+ else:
+ toolchain_info = _python_register_toolchains(
+ toolchain_name,
+ toolchain_attr,
+ module = mod,
+ )
+ global_toolchain_versions[toolchain_version] = toolchain_info
+
+ if is_default:
+ # This toolchain is setting the default, but the actual
+ # registration was performed previously, by a different module.
+ if toolchain_info == None:
+ default_toolchain = global_toolchain_versions[toolchain_version]
+
+ # Remove it because later code will add it at the end to
+ # ensure it is last in the list.
+ toolchains.remove(default_toolchain)
+ else:
+ default_toolchain = toolchain_info
+ elif toolchain_info:
+ toolchains.append(toolchain_info)
+
+ # A default toolchain is required so that the non-version-specific rules
+ # are able to match a toolchain.
+ if default_toolchain == None:
+ fail("No default Python toolchain configured. Is rules_python missing `is_default=True`?")
+ elif default_toolchain.python_version not in global_toolchain_versions:
+ fail('Default version "{python_version}" selected by module ' +
+ '"{module_name}", but no toolchain with that version registered'.format(
+ python_version = default_toolchain.python_version,
+ module_name = default_toolchain.module.name,
+ ))
+
+ # The last toolchain in the BUILD file is set as the default
+ # toolchain. We need the default last.
+ toolchains.append(default_toolchain)
+
+ if len(toolchains) > _MAX_NUM_TOOLCHAINS:
+ fail("more than {} python versions are not supported".format(_MAX_NUM_TOOLCHAINS))
+
+ # Create the pythons_hub repo for the interpreter meta data and the
+ # the various toolchains.
+ hub_repo(
+ name = "pythons_hub",
+ default_python_version = default_toolchain.python_version,
+ toolchain_prefixes = [
+ _toolchain_prefix(index, toolchain.name)
+ for index, toolchain in enumerate(toolchains)
+ ],
+ toolchain_python_versions = [t.python_version for t in toolchains],
+ # The last toolchain is the default; it can't have version constraints
+ # Despite the implication of the arg name, the values are strs, not bools
+ toolchain_set_python_version_constraints = [
+ "True" if i != len(toolchains) - 1 else "False"
+ for i in range(len(toolchains))
+ ],
+ toolchain_user_repository_names = [t.name for t in toolchains],
+ )
+
+ # This is require in order to support multiple version py_test
+ # and py_binary
+ multi_toolchain_aliases(
+ name = "python_versions",
+ python_versions = {
+ version: toolchain.name
+ for version, toolchain in global_toolchain_versions.items()
+ },
+ )
+
+def _fail_duplicate_module_toolchain_version(version, module):
+ fail(("Duplicate module toolchain version: module '{module}' attempted " +
+ "to use version '{version}' multiple times in itself").format(
+ version = version,
+ module = module,
+ ))
+
+def _warn_duplicate_global_toolchain_version(version, first, second_toolchain_name, second_module_name):
+ _print_warn((
+ "Ignoring toolchain '{second_toolchain}' from module '{second_module}': " +
+ "Toolchain '{first_toolchain}' from module '{first_module}' " +
+ "already registered Python version {version} and has precedence"
+ ).format(
+ first_toolchain = first.name,
+ first_module = first.module.name,
+ second_module = second_module_name,
+ second_toolchain = second_toolchain_name,
+ version = version,
+ ))
+
+def _fail_multiple_default_toolchains(first, second):
+ fail(("Multiple default toolchains: only one toolchain " +
+ "can have is_default=True. First default " +
+ "was toolchain '{first}'. Second was '{second}'").format(
+ first = first,
+ second = second,
+ ))
+
+python = module_extension(
+ doc = """Bzlmod extension that is used to register Python toolchains.
+""",
+ implementation = _python_impl,
+ tag_classes = {
+ "toolchain": tag_class(
+ doc = """Tag class used to register Python toolchains.
+Use this tag class to register one or more Python toolchains. This class
+is also potentially called by sub modules. The following covers different
+business rules and use cases.
+
+Toolchains in the Root Module
+
+This class registers all toolchains in the root module.
+
+Toolchains in Sub Modules
+
+It will create a toolchain that is in a sub module, if the toolchain
+of the same name does not exist in the root module. The extension stops name
+clashing between toolchains in the root module and toolchains in sub modules.
+You cannot configure more than one toolchain as the default toolchain.
+
+Toolchain set as the default version
+
+This extension will not create a toolchain that exists in a sub module,
+if the sub module toolchain is marked as the default version. If you have
+more than one toolchain in your root module, you need to set one of the
+toolchains as the default version. If there is only one toolchain it
+is set as the default toolchain.
+
+Toolchain repository name
+
+A toolchain's repository name uses the format `python_{major}_{minor}`, e.g.
+`python_3_10`. The `major` and `minor` components are
+`major` and `minor` are the Python version from the `python_version` attribute.
+""",
+ 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,
+ ),
+ "is_default": attr.bool(
+ mandatory = False,
+ doc = "Whether the toolchain is the default version",
+ ),
+ "python_version": attr.string(
+ mandatory = True,
+ doc = "The Python version, in `major.minor` format, e.g " +
+ "'3.12', to create a toolchain for. Patch level " +
+ "granularity (e.g. '3.12.1') is not supported.",
+ ),
+ },
+ ),
+ },
+)
diff --git a/python/extensions/private/pythons_hub.bzl b/python/private/bzlmod/pythons_hub.bzl
index a64f203..5f536f3 100644
--- a/python/extensions/private/pythons_hub.bzl
+++ b/python/private/bzlmod/pythons_hub.bzl
@@ -14,7 +14,8 @@
"Repo rule used by bzlmod extension to create a repo that has a map of Python interpreters and their labels"
-load("//python:versions.bzl", "MINOR_MAPPING", "WINDOWS_NAME")
+load("//python:versions.bzl", "WINDOWS_NAME")
+load("//python/private:full_version.bzl", "full_version")
load(
"//python/private:toolchains_repo.bzl",
"get_host_os_arch",
@@ -28,13 +29,19 @@ def _have_same_length(*lists):
fail("expected at least one list")
return len({len(length): None for length in lists}) == 1
-def _get_version(python_version):
- # we need to get the MINOR_MAPPING or use the full version
- if python_version in MINOR_MAPPING:
- python_version = MINOR_MAPPING[python_version]
- return python_version
+_HUB_BUILD_FILE_TEMPLATE = """\
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-def _python_toolchain_build_file_content(
+bzl_library(
+ name = "interpreters_bzl",
+ srcs = ["interpreters.bzl"],
+ visibility = ["@rules_python//:__subpackages__"],
+)
+
+{toolchains}
+"""
+
+def _hub_build_file_content(
prefixes,
python_versions,
set_python_version_constraints,
@@ -53,15 +60,17 @@ def _python_toolchain_build_file_content(
# Iterate over the length of python_versions and call
# build the toolchain content by calling python_toolchain_build_file_content
- return "\n".join([python_toolchain_build_file_content(
+ toolchains = "\n".join([python_toolchain_build_file_content(
prefix = prefixes[i],
- python_version = _get_version(python_versions[i]),
+ python_version = full_version(python_versions[i]),
set_python_version_constraint = set_python_version_constraints[i],
user_repository_name = user_repository_names[i],
rules_python = rules_python,
) for i in range(len(python_versions))])
-_build_file_for_hub_template = """
+ return _HUB_BUILD_FILE_TEMPLATE.format(toolchains = toolchains)
+
+_interpreters_bzl_template = """
INTERPRETER_LABELS = {{
{interpreter_labels}
}}
@@ -77,7 +86,7 @@ def _hub_repo_impl(rctx):
# write them to the BUILD file.
rctx.file(
"BUILD.bazel",
- _python_toolchain_build_file_content(
+ _hub_build_file_content(
rctx.attr.toolchain_prefixes,
rctx.attr.toolchain_python_versions,
rctx.attr.toolchain_set_python_version_constraints,
@@ -102,7 +111,7 @@ def _hub_repo_impl(rctx):
rctx.file(
"interpreters.bzl",
- _build_file_for_hub_template.format(
+ _interpreters_bzl_template.format(
interpreter_labels = interpreter_labels,
default_python_version = rctx.attr.default_python_version,
),
diff --git a/python/private/bzlmod/requirements.bzl.tmpl b/python/private/bzlmod/requirements.bzl.tmpl
new file mode 100644
index 0000000..b99322d
--- /dev/null
+++ b/python/private/bzlmod/requirements.bzl.tmpl
@@ -0,0 +1,46 @@
+"""Starlark representation of locked requirements.
+
+@generated by rules_python pip.parse bzlmod extension.
+"""
+
+load("@rules_python//python:pip.bzl", "pip_utils")
+
+all_requirements = %%ALL_REQUIREMENTS%%
+
+all_whl_requirements_by_package = %%ALL_WHL_REQUIREMENTS_BY_PACKAGE%%
+
+all_whl_requirements = all_whl_requirements_by_package.values()
+
+all_data_requirements = %%ALL_DATA_REQUIREMENTS%%
+
+def requirement(name):
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "pkg")
+
+def whl_requirement(name):
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "whl")
+
+def data_requirement(name):
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "data")
+
+def dist_info_requirement(name):
+ return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "dist_info")
+
+def entry_point(pkg, script = None):
+ """entry_point returns the target of the canonical label of the package entrypoints.
+ """
+ actual_script = script or pkg
+
+ fail("""Please replace this instance of entry_point with the following:
+
+```
+load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
+
+py_console_script_binary(
+ name = "{pkg}",
+ pkg = "@%%NAME%%//{pkg}",{script}
+)
+```
+""".format(
+ pkg = pip_utils.normalize_name(pkg),
+ script = "" if not script else "\n script = \"%s\"," % actual_script,
+ ))
diff --git a/python/private/common/BUILD.bazel b/python/private/common/BUILD.bazel
new file mode 100644
index 0000000..e69eaff
--- /dev/null
+++ b/python/private/common/BUILD.bazel
@@ -0,0 +1,207 @@
+# 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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+package(
+ default_visibility = ["//python:__subpackages__"],
+)
+
+bzl_library(
+ name = "attributes_bazel_bzl",
+ srcs = ["attributes_bazel.bzl"],
+)
+
+bzl_library(
+ name = "attributes_bzl",
+ srcs = ["attributes.bzl"],
+ deps = [
+ ":common_bzl",
+ ":providers_bzl",
+ ":py_internal_bzl",
+ ":semantics_bzl",
+ "//python/private:reexports_bzl",
+ ],
+)
+
+bzl_library(
+ name = "cc_helper_bzl",
+ srcs = ["cc_helper.bzl"],
+ deps = [":py_internal_bzl"],
+)
+
+bzl_library(
+ name = "common_bazel_bzl",
+ srcs = ["common_bazel.bzl"],
+ deps = [
+ ":common_bzl",
+ ":providers_bzl",
+ ":py_internal_bzl",
+ "@bazel_skylib//lib:paths",
+ ],
+)
+
+bzl_library(
+ name = "common_bzl",
+ srcs = ["common.bzl"],
+ deps = [
+ ":cc_helper_bzl",
+ ":providers_bzl",
+ ":py_internal_bzl",
+ ":semantics_bzl",
+ "//python/private:reexports_bzl",
+ ],
+)
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+)
+
+bzl_library(
+ name = "providers_bzl",
+ srcs = ["providers.bzl"],
+ deps = [
+ ":semantics_bzl",
+ "//python/private:util_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_binary_macro_bazel_bzl",
+ srcs = ["py_binary_macro_bazel.bzl"],
+ deps = [
+ ":common_bzl",
+ ":py_binary_rule_bazel_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_binary_rule_bazel_bzl",
+ srcs = ["py_binary_rule_bazel.bzl"],
+ deps = [
+ ":attributes_bzl",
+ ":py_executable_bazel_bzl",
+ ":semantics_bzl",
+ "@bazel_skylib//lib:dicts",
+ ],
+)
+
+bzl_library(
+ name = "py_executable_bazel_bzl",
+ srcs = ["py_executable_bazel.bzl"],
+ deps = [
+ ":attributes_bazel_bzl",
+ ":common_bazel_bzl",
+ ":common_bzl",
+ ":providers_bzl",
+ ":py_executable_bzl",
+ ":py_internal_bzl",
+ ":semantics_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_executable_bzl",
+ srcs = ["py_executable.bzl"],
+ deps = [
+ ":attributes_bzl",
+ ":cc_helper_bzl",
+ ":common_bzl",
+ ":providers_bzl",
+ ":py_internal_bzl",
+ "@bazel_skylib//lib:dicts",
+ ],
+)
+
+bzl_library(
+ name = "py_internal_bzl",
+ srcs = ["py_internal.bzl"],
+ deps = ["@rules_python_internal//:py_internal_bzl"],
+)
+
+bzl_library(
+ name = "py_library_bzl",
+ srcs = ["py_library.bzl"],
+ deps = [
+ ":attributes_bzl",
+ ":common_bzl",
+ ":providers_bzl",
+ ":py_internal_bzl",
+ "@bazel_skylib//lib:dicts",
+ ],
+)
+
+bzl_library(
+ name = "py_library_macro_bazel_bzl",
+ srcs = ["py_library_macro_bazel.bzl"],
+ deps = [":py_library_rule_bazel_bzl"],
+)
+
+bzl_library(
+ name = "py_library_rule_bazel_bzl",
+ srcs = ["py_library_rule_bazel.bzl"],
+ deps = [
+ ":attributes_bazel_bzl",
+ ":common_bazel_bzl",
+ ":common_bzl",
+ ":py_library_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_runtime_macro_bzl",
+ srcs = ["py_runtime_macro.bzl"],
+ deps = [":py_runtime_rule_bzl"],
+)
+
+bzl_library(
+ name = "py_runtime_rule_bzl",
+ srcs = ["py_runtime_rule.bzl"],
+ deps = [
+ ":attributes_bzl",
+ ":providers_bzl",
+ ":py_internal_bzl",
+ "//python/private:reexports_bzl",
+ "//python/private:util_bzl",
+ "@bazel_skylib//lib:dicts",
+ "@bazel_skylib//lib:paths",
+ ],
+)
+
+bzl_library(
+ name = "py_test_macro_bazel_bzl",
+ srcs = ["py_test_macro_bazel.bzl"],
+ deps = [
+ ":common_bazel_bzl",
+ ":py_test_rule_bazel_bzl",
+ ],
+)
+
+bzl_library(
+ name = "py_test_rule_bazel_bzl",
+ srcs = ["py_test_rule_bazel.bzl"],
+ deps = [
+ ":attributes_bzl",
+ ":common_bzl",
+ ":py_executable_bazel_bzl",
+ ":semantics_bzl",
+ "@bazel_skylib//lib:dicts",
+ ],
+)
+
+bzl_library(
+ name = "semantics_bzl",
+ srcs = ["semantics.bzl"],
+)
diff --git a/python/private/common/attributes.bzl b/python/private/common/attributes.bzl
new file mode 100644
index 0000000..b26d02c
--- /dev/null
+++ b/python/private/common/attributes.bzl
@@ -0,0 +1,245 @@
+# 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.
+"""Attributes for Python rules."""
+
+load("//python/private:reexports.bzl", "BuiltinPyInfo")
+load(":common.bzl", "union_attrs")
+load(":providers.bzl", "PyInfo")
+load(":py_internal.bzl", "py_internal")
+load(
+ ":semantics.bzl",
+ "DEPS_ATTR_ALLOW_RULES",
+ "SRCS_ATTR_ALLOW_FILES",
+)
+
+# TODO: Load CcInfo from rules_cc
+_CcInfo = CcInfo
+_PackageSpecificationInfo = getattr(py_internal, "PackageSpecificationInfo", None)
+
+_STAMP_VALUES = [-1, 0, 1]
+
+def create_stamp_attr(**kwargs):
+ return {"stamp": attr.int(values = _STAMP_VALUES, **kwargs)}
+
+def create_srcs_attr(*, mandatory):
+ return {
+ "srcs": attr.label_list(
+ # Google builds change the set of allowed files.
+ allow_files = SRCS_ATTR_ALLOW_FILES,
+ mandatory = mandatory,
+ # Necessary for --compile_one_dependency to work.
+ flags = ["DIRECT_COMPILE_TIME_INPUT"],
+ ),
+ }
+
+SRCS_VERSION_ALL_VALUES = ["PY2", "PY2ONLY", "PY2AND3", "PY3", "PY3ONLY"]
+SRCS_VERSION_NON_CONVERSION_VALUES = ["PY2AND3", "PY2ONLY", "PY3ONLY"]
+
+def create_srcs_version_attr(values):
+ return {
+ "srcs_version": attr.string(
+ default = "PY2AND3",
+ values = values,
+ ),
+ }
+
+def copy_common_binary_kwargs(kwargs):
+ return {
+ key: kwargs[key]
+ for key in BINARY_ATTR_NAMES
+ if key in kwargs
+ }
+
+def copy_common_test_kwargs(kwargs):
+ return {
+ key: kwargs[key]
+ for key in TEST_ATTR_NAMES
+ if key in kwargs
+ }
+
+CC_TOOLCHAIN = {
+ # NOTE: The `cc_helper.find_cpp_toolchain()` function expects the attribute
+ # name to be this name.
+ "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
+}
+
+# The common "data" attribute definition.
+DATA_ATTRS = {
+ # NOTE: The "flags" attribute is deprecated, but there isn't an alternative
+ # way to specify that constraints should be ignored.
+ "data": attr.label_list(
+ allow_files = True,
+ flags = ["SKIP_CONSTRAINTS_OVERRIDE"],
+ ),
+}
+
+def _create_native_rules_allowlist_attrs():
+ if py_internal:
+ # The fragment and name are validated when configuration_field is called
+ default = configuration_field(
+ fragment = "py",
+ name = "native_rules_allowlist",
+ )
+
+ # A None provider isn't allowed
+ providers = [_PackageSpecificationInfo]
+ else:
+ default = None
+ providers = []
+
+ return {
+ "_native_rules_allowlist": attr.label(
+ default = default,
+ providers = providers,
+ ),
+ }
+
+NATIVE_RULES_ALLOWLIST_ATTRS = _create_native_rules_allowlist_attrs()
+
+# Attributes common to all rules.
+COMMON_ATTRS = union_attrs(
+ DATA_ATTRS,
+ NATIVE_RULES_ALLOWLIST_ATTRS,
+ {
+ # NOTE: This attribute is deprecated and slated for removal.
+ "distribs": attr.string_list(),
+ # TODO(b/148103851): This attribute is deprecated and slated for
+ # removal.
+ # NOTE: The license attribute is missing in some Java integration tests,
+ # so fallback to a regular string_list for that case.
+ # buildifier: disable=attr-license
+ "licenses": attr.license() if hasattr(attr, "license") else attr.string_list(),
+ },
+ allow_none = True,
+)
+
+# Attributes common to rules accepting Python sources and deps.
+PY_SRCS_ATTRS = union_attrs(
+ {
+ "deps": attr.label_list(
+ providers = [
+ [PyInfo],
+ [_CcInfo],
+ [BuiltinPyInfo],
+ ],
+ # TODO(b/228692666): Google-specific; remove these allowances once
+ # the depot is cleaned up.
+ allow_rules = DEPS_ATTR_ALLOW_RULES,
+ ),
+ # Required attribute, but details vary by rule.
+ # Use create_srcs_attr to create one.
+ "srcs": None,
+ # NOTE: In Google, this attribute is deprecated, and can only
+ # effectively be PY3 or PY3ONLY. Externally, with Bazel, this attribute
+ # has a separate story.
+ # Required attribute, but the details vary by rule.
+ # Use create_srcs_version_attr to create one.
+ "srcs_version": None,
+ },
+ allow_none = True,
+)
+
+# Attributes specific to Python executable-equivalent rules. Such rules may not
+# accept Python sources (e.g. some packaged-version of a py_test/py_binary), but
+# still accept Python source-agnostic settings.
+AGNOSTIC_EXECUTABLE_ATTRS = union_attrs(
+ DATA_ATTRS,
+ {
+ "env": attr.string_dict(
+ doc = """\
+Dictionary of strings; optional; values are subject to `$(location)` and "Make
+variable" substitution.
+
+Specifies additional environment variables to set when the target is executed by
+`test` or `run`.
+""",
+ ),
+ # The value is required, but varies by rule and/or rule type. Use
+ # create_stamp_attr to create one.
+ "stamp": None,
+ },
+ allow_none = True,
+)
+
+# Attributes specific to Python test-equivalent executable rules. Such rules may
+# not accept Python sources (e.g. some packaged-version of a py_test/py_binary),
+# but still accept Python source-agnostic settings.
+AGNOSTIC_TEST_ATTRS = union_attrs(
+ AGNOSTIC_EXECUTABLE_ATTRS,
+ # Tests have stamping disabled by default.
+ create_stamp_attr(default = 0),
+ {
+ "env_inherit": attr.string_list(
+ doc = """\
+List of strings; optional
+
+Specifies additional environment variables to inherit from the external
+environment when the test is executed by bazel test.
+""",
+ ),
+ # TODO(b/176993122): Remove when Bazel automatically knows to run on darwin.
+ "_apple_constraints": attr.label_list(
+ default = [
+ "@platforms//os:ios",
+ "@platforms//os:macos",
+ "@platforms//os:tvos",
+ "@platforms//os:visionos",
+ "@platforms//os:watchos",
+ ],
+ ),
+ },
+)
+
+# Attributes specific to Python binary-equivalent executable rules. Such rules may
+# not accept Python sources (e.g. some packaged-version of a py_test/py_binary),
+# but still accept Python source-agnostic settings.
+AGNOSTIC_BINARY_ATTRS = union_attrs(
+ AGNOSTIC_EXECUTABLE_ATTRS,
+ create_stamp_attr(default = -1),
+)
+
+# Attribute names common to all Python rules
+COMMON_ATTR_NAMES = [
+ "compatible_with",
+ "deprecation",
+ "distribs", # NOTE: Currently common to all rules, but slated for removal
+ "exec_compatible_with",
+ "exec_properties",
+ "features",
+ "restricted_to",
+ "tags",
+ "target_compatible_with",
+ # NOTE: The testonly attribute requires careful handling: None/unset means
+ # to use the `package(default_testonly`) value, which isn't observable
+ # during the loading phase.
+ "testonly",
+ "toolchains",
+ "visibility",
+] + COMMON_ATTRS.keys()
+
+# Attribute names common to all test=True rules
+TEST_ATTR_NAMES = COMMON_ATTR_NAMES + [
+ "args",
+ "size",
+ "timeout",
+ "flaky",
+ "shard_count",
+ "local",
+] + AGNOSTIC_TEST_ATTRS.keys()
+
+# Attribute names common to all executable=True rules
+BINARY_ATTR_NAMES = COMMON_ATTR_NAMES + [
+ "args",
+ "output_licenses", # NOTE: Common to all rules, but slated for removal
+] + AGNOSTIC_BINARY_ATTRS.keys()
diff --git a/python/private/common/attributes_bazel.bzl b/python/private/common/attributes_bazel.bzl
new file mode 100644
index 0000000..f87245d
--- /dev/null
+++ b/python/private/common/attributes_bazel.bzl
@@ -0,0 +1,30 @@
+# 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.
+"""Attributes specific to the Bazel implementation of the Python rules."""
+
+IMPORTS_ATTRS = {
+ "imports": attr.string_list(
+ doc = """
+List of import directories to be added to the PYTHONPATH.
+
+Subject to "Make variable" substitution. These import directories will be added
+for this rule and all rules that depend on it (note: not the rules this rule
+depends on. Each directory will be added to `PYTHONPATH` by `py_binary` rules
+that depend on this rule. The strings are repo-runfiles-root relative,
+
+Absolute paths (paths that start with `/`) and paths that references a path
+above the execution root are not allowed and will result in an error.
+""",
+ ),
+}
diff --git a/python/private/common/cc_helper.bzl b/python/private/common/cc_helper.bzl
new file mode 100644
index 0000000..552b42e
--- /dev/null
+++ b/python/private/common/cc_helper.bzl
@@ -0,0 +1,23 @@
+# 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 RULE IMPLEMENTATION ONLY: Do not use outside of the rule implementations and their tests.
+
+Adapter for accessing Bazel's internal cc_helper.
+
+These may change at any time and are closely coupled to the rule implementation.
+"""
+
+load(":py_internal.bzl", "py_internal")
+
+cc_helper = getattr(py_internal, "cc_helper", None)
diff --git a/python/private/common/common.bzl b/python/private/common/common.bzl
new file mode 100644
index 0000000..75c117f
--- /dev/null
+++ b/python/private/common/common.bzl
@@ -0,0 +1,537 @@
+# 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.
+"""Various things common to Bazel and Google rule implementations."""
+
+load("//python/private:reexports.bzl", "BuiltinPyInfo")
+load(":cc_helper.bzl", "cc_helper")
+load(":providers.bzl", "PyInfo")
+load(":py_internal.bzl", "py_internal")
+load(
+ ":semantics.bzl",
+ "NATIVE_RULES_MIGRATION_FIX_CMD",
+ "NATIVE_RULES_MIGRATION_HELP_URL",
+)
+
+_testing = testing
+_platform_common = platform_common
+_coverage_common = coverage_common
+_py_builtins = py_internal
+PackageSpecificationInfo = getattr(py_internal, "PackageSpecificationInfo", None)
+
+TOOLCHAIN_TYPE = "@bazel_tools//tools/python:toolchain_type"
+
+# Extensions without the dot
+_PYTHON_SOURCE_EXTENSIONS = ["py"]
+
+# NOTE: Must stay in sync with the value used in rules_python
+_MIGRATION_TAG = "__PYTHON_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__"
+
+def create_binary_semantics_struct(
+ *,
+ create_executable,
+ get_cc_details_for_binary,
+ get_central_uncachable_version_file,
+ get_coverage_deps,
+ get_debugger_deps,
+ get_extra_common_runfiles_for_binary,
+ get_extra_providers,
+ get_extra_write_build_data_env,
+ get_interpreter_path,
+ get_imports,
+ get_native_deps_dso_name,
+ get_native_deps_user_link_flags,
+ get_stamp_flag,
+ maybe_precompile,
+ should_build_native_deps_dso,
+ should_create_init_files,
+ should_include_build_data):
+ """Helper to ensure a semantics struct has all necessary fields.
+
+ Call this instead of a raw call to `struct(...)`; it'll help ensure all
+ the necessary functions are being correctly provided.
+
+ Args:
+ create_executable: Callable; creates a binary's executable output. See
+ py_executable.bzl#py_executable_base_impl for details.
+ get_cc_details_for_binary: Callable that returns a `CcDetails` struct; see
+ `create_cc_detail_struct`.
+ get_central_uncachable_version_file: Callable that returns an optional
+ Artifact; this artifact is special: it is never cached and is a copy
+ of `ctx.version_file`; see py_builtins.copy_without_caching
+ get_coverage_deps: Callable that returns a list of Targets for making
+ coverage work; only called if coverage is enabled.
+ get_debugger_deps: Callable that returns a list of Targets that provide
+ custom debugger support; only called for target-configuration.
+ get_extra_common_runfiles_for_binary: Callable that returns a runfiles
+ object of extra runfiles a binary should include.
+ get_extra_providers: Callable that returns extra providers; see
+ py_executable.bzl#_create_providers for details.
+ get_extra_write_build_data_env: Callable that returns a dict[str, str]
+ of additional environment variable to pass to build data generation.
+ get_interpreter_path: Callable that returns an optional string, which is
+ the path to the Python interpreter to use for running the binary.
+ get_imports: Callable that returns a list of the target's import
+ paths (from the `imports` attribute, so just the target's own import
+ path strings, not from dependencies).
+ get_native_deps_dso_name: Callable that returns a string, which is the
+ basename (with extension) of the native deps DSO library.
+ get_native_deps_user_link_flags: Callable that returns a list of strings,
+ which are any extra linker flags to pass onto the native deps DSO
+ linking action.
+ get_stamp_flag: Callable that returns bool of if the --stamp flag was
+ enabled or not.
+ maybe_precompile: Callable that may optional precompile the input `.py`
+ sources and returns the full set of desired outputs derived from
+ the source files (e.g., both py and pyc, only one of them, etc).
+ should_build_native_deps_dso: Callable that returns bool; True if
+ building a native deps DSO is supported, False if not.
+ should_create_init_files: Callable that returns bool; True if
+ `__init__.py` files should be generated, False if not.
+ should_include_build_data: Callable that returns bool; True if
+ build data should be generated, False if not.
+ Returns:
+ A "BinarySemantics" struct.
+ """
+ return struct(
+ # keep-sorted
+ create_executable = create_executable,
+ get_cc_details_for_binary = get_cc_details_for_binary,
+ get_central_uncachable_version_file = get_central_uncachable_version_file,
+ get_coverage_deps = get_coverage_deps,
+ get_debugger_deps = get_debugger_deps,
+ get_extra_common_runfiles_for_binary = get_extra_common_runfiles_for_binary,
+ get_extra_providers = get_extra_providers,
+ get_extra_write_build_data_env = get_extra_write_build_data_env,
+ get_imports = get_imports,
+ get_interpreter_path = get_interpreter_path,
+ get_native_deps_dso_name = get_native_deps_dso_name,
+ get_native_deps_user_link_flags = get_native_deps_user_link_flags,
+ get_stamp_flag = get_stamp_flag,
+ maybe_precompile = maybe_precompile,
+ should_build_native_deps_dso = should_build_native_deps_dso,
+ should_create_init_files = should_create_init_files,
+ should_include_build_data = should_include_build_data,
+ )
+
+def create_library_semantics_struct(
+ *,
+ get_cc_info_for_library,
+ get_imports,
+ maybe_precompile):
+ """Create a `LibrarySemantics` struct.
+
+ Call this instead of a raw call to `struct(...)`; it'll help ensure all
+ the necessary functions are being correctly provided.
+
+ Args:
+ get_cc_info_for_library: Callable that returns a CcInfo for the library;
+ see py_library_impl for arg details.
+ get_imports: Callable; see create_binary_semantics_struct.
+ maybe_precompile: Callable; see create_binary_semantics_struct.
+ Returns:
+ a `LibrarySemantics` struct.
+ """
+ return struct(
+ # keep sorted
+ get_cc_info_for_library = get_cc_info_for_library,
+ get_imports = get_imports,
+ maybe_precompile = maybe_precompile,
+ )
+
+def create_cc_details_struct(
+ *,
+ cc_info_for_propagating,
+ cc_info_for_self_link,
+ cc_info_with_extra_link_time_libraries,
+ extra_runfiles,
+ cc_toolchain):
+ """Creates a CcDetails struct.
+
+ Args:
+ cc_info_for_propagating: CcInfo that is propagated out of the target
+ by returning it within a PyCcLinkParamsProvider object.
+ cc_info_for_self_link: CcInfo that is used when linking for the
+ binary (or its native deps DSO) itself. This may include extra
+ information that isn't propagating (e.g. a custom malloc)
+ cc_info_with_extra_link_time_libraries: CcInfo of extra link time
+ libraries that MUST come after `cc_info_for_self_link` (or possibly
+ always last; not entirely clear) when passed to
+ `link.linking_contexts`.
+ extra_runfiles: runfiles of extra files needed at runtime, usually as
+ part of `cc_info_with_extra_link_time_libraries`; should be added to
+ runfiles.
+ cc_toolchain: CcToolchain that should be used when building.
+
+ Returns:
+ A `CcDetails` struct.
+ """
+ return struct(
+ cc_info_for_propagating = cc_info_for_propagating,
+ cc_info_for_self_link = cc_info_for_self_link,
+ cc_info_with_extra_link_time_libraries = cc_info_with_extra_link_time_libraries,
+ extra_runfiles = extra_runfiles,
+ cc_toolchain = cc_toolchain,
+ )
+
+def create_executable_result_struct(*, extra_files_to_build, output_groups):
+ """Creates a `CreateExecutableResult` struct.
+
+ This is the return value type of the semantics create_executable function.
+
+ Args:
+ extra_files_to_build: depset of File; additional files that should be
+ included as default outputs.
+ output_groups: dict[str, depset[File]]; additional output groups that
+ should be returned.
+
+ Returns:
+ A `CreateExecutableResult` struct.
+ """
+ return struct(
+ extra_files_to_build = extra_files_to_build,
+ output_groups = output_groups,
+ )
+
+def union_attrs(*attr_dicts, allow_none = False):
+ """Helper for combining and building attriute dicts for rules.
+
+ Similar to dict.update, except:
+ * Duplicate keys raise an error if they aren't equal. This is to prevent
+ unintentionally replacing an attribute with a potentially incompatible
+ definition.
+ * None values are special: They mean the attribute is required, but the
+ value should be provided by another attribute dict (depending on the
+ `allow_none` arg).
+ Args:
+ *attr_dicts: The dicts to combine.
+ allow_none: bool, if True, then None values are allowed. If False,
+ then one of `attrs_dicts` must set a non-None value for keys
+ with a None value.
+
+ Returns:
+ dict of attributes.
+ """
+ result = {}
+ missing = {}
+ for attr_dict in attr_dicts:
+ for attr_name, value in attr_dict.items():
+ if value == None and not allow_none:
+ if attr_name not in result:
+ missing[attr_name] = None
+ else:
+ if attr_name in missing:
+ missing.pop(attr_name)
+
+ if attr_name not in result or result[attr_name] == None:
+ result[attr_name] = value
+ elif value != None and result[attr_name] != value:
+ fail("Duplicate attribute name: '{}': existing={}, new={}".format(
+ attr_name,
+ result[attr_name],
+ value,
+ ))
+
+ # Else, they're equal, so do nothing. This allows merging dicts
+ # that both define the same key from a common place.
+
+ if missing and not allow_none:
+ fail("Required attributes missing: " + csv(missing.keys()))
+ return result
+
+def csv(values):
+ """Convert a list of strings to comma separated value string."""
+ return ", ".join(sorted(values))
+
+def filter_to_py_srcs(srcs):
+ """Filters .py files from the given list of files"""
+
+ # TODO(b/203567235): Get the set of recognized extensions from
+ # elsewhere, as there may be others. e.g. Bazel recognizes .py3
+ # as a valid extension.
+ return [f for f in srcs if f.extension == "py"]
+
+def collect_imports(ctx, semantics):
+ return depset(direct = semantics.get_imports(ctx), transitive = [
+ dep[PyInfo].imports
+ for dep in ctx.attr.deps
+ if PyInfo in dep
+ ] + [
+ dep[BuiltinPyInfo].imports
+ for dep in ctx.attr.deps
+ if BuiltinPyInfo in dep
+ ])
+
+def collect_runfiles(ctx, files):
+ """Collects the necessary files from the rule's context.
+
+ This presumes the ctx is for a py_binary, py_test, or py_library rule.
+
+ Args:
+ ctx: rule ctx
+ files: depset of extra files to include in the runfiles.
+ Returns:
+ runfiles necessary for the ctx's target.
+ """
+ return ctx.runfiles(
+ transitive_files = files,
+ # This little arg carries a lot of weight, but because Starlark doesn't
+ # have a way to identify if a target is just a File, the equivalent
+ # logic can't be re-implemented in pure-Starlark.
+ #
+ # Under the hood, it calls the Java `Runfiles#addRunfiles(ctx,
+ # DEFAULT_RUNFILES)` method, which is the what the Java implementation
+ # of the Python rules originally did, and the details of how that method
+ # works have become relied on in various ways. Specifically, what it
+ # does is visit the srcs, deps, and data attributes in the following
+ # ways:
+ #
+ # For each target in the "data" attribute...
+ # If the target is a File, then add that file to the runfiles.
+ # Otherwise, add the target's **data runfiles** to the runfiles.
+ #
+ # Note that, contray to best practice, the default outputs of the
+ # targets in `data` are *not* added, nor are the default runfiles.
+ #
+ # This ends up being important for several reasons, some of which are
+ # specific to Google-internal features of the rules.
+ # * For Python executables, we have to use `data_runfiles` to avoid
+ # conflicts for the build data files. Such files have
+ # target-specific content, but uses a fixed location, so if a
+ # binary has another binary in `data`, and both try to specify a
+ # file for that file path, then a warning is printed and an
+ # arbitrary one will be used.
+ # * For rules with _entirely_ different sets of files in data runfiles
+ # vs default runfiles vs default outputs. For example,
+ # proto_library: documented behavior of this rule is that putting it
+ # in the `data` attribute will cause the transitive closure of
+ # `.proto` source files to be included. This set of sources is only
+ # in the `data_runfiles` (`default_runfiles` is empty).
+ # * For rules with a _subset_ of files in data runfiles. For example,
+ # a certain Google rule used for packaging arbitrary binaries will
+ # generate multiple versions of a binary (e.g. different archs,
+ # stripped vs un-stripped, etc) in its default outputs, but only
+ # one of them in the runfiles; this helps avoid large, unused
+ # binaries contributing to remote executor input limits.
+ #
+ # Unfortunately, the above behavior also results in surprising behavior
+ # in some cases. For example, simple custom rules that only return their
+ # files in their default outputs won't have their files included. Such
+ # cases must either return their files in runfiles, or use `filegroup()`
+ # which will do so for them.
+ #
+ # For each target in "srcs" and "deps"...
+ # Add the default runfiles of the target to the runfiles. While this
+ # is desirable behavior, it also ends up letting a `py_library`
+ # be put in `srcs` and still mostly work.
+ # TODO(b/224640180): Reject py_library et al rules in srcs.
+ collect_default = True,
+ )
+
+def create_py_info(ctx, *, direct_sources, imports):
+ """Create PyInfo provider.
+
+ Args:
+ ctx: rule ctx.
+ direct_sources: depset of Files; the direct, raw `.py` sources for the
+ target. This should only be Python source files. It should not
+ include pyc files.
+ imports: depset of strings; the import path values to propagate.
+
+ Returns:
+ A tuple of the PyInfo instance and a depset of the
+ transitive sources collected from dependencies (the latter is only
+ necessary for deprecated extra actions support).
+ """
+ uses_shared_libraries = False
+ has_py2_only_sources = ctx.attr.srcs_version in ("PY2", "PY2ONLY")
+ has_py3_only_sources = ctx.attr.srcs_version in ("PY3", "PY3ONLY")
+ transitive_sources_depsets = [] # list of depsets
+ transitive_sources_files = [] # list of Files
+ for target in ctx.attr.deps:
+ # PyInfo may not be present e.g. cc_library rules.
+ if PyInfo in target or BuiltinPyInfo in target:
+ info = _get_py_info(target)
+ transitive_sources_depsets.append(info.transitive_sources)
+ uses_shared_libraries = uses_shared_libraries or info.uses_shared_libraries
+ has_py2_only_sources = has_py2_only_sources or info.has_py2_only_sources
+ has_py3_only_sources = has_py3_only_sources or info.has_py3_only_sources
+ else:
+ # TODO(b/228692666): Remove this once non-PyInfo targets are no
+ # longer supported in `deps`.
+ files = target.files.to_list()
+ for f in files:
+ if f.extension == "py":
+ transitive_sources_files.append(f)
+ uses_shared_libraries = (
+ uses_shared_libraries or
+ cc_helper.is_valid_shared_library_artifact(f)
+ )
+ deps_transitive_sources = depset(
+ direct = transitive_sources_files,
+ transitive = transitive_sources_depsets,
+ )
+
+ # We only look at data to calculate uses_shared_libraries, if it's already
+ # true, then we don't need to waste time looping over it.
+ if not uses_shared_libraries:
+ # Similar to the above, except we only calculate uses_shared_libraries
+ for target in ctx.attr.data:
+ # TODO(b/234730058): Remove checking for PyInfo in data once depot
+ # cleaned up.
+ if PyInfo in target or BuiltinPyInfo in target:
+ info = _get_py_info(target)
+ uses_shared_libraries = info.uses_shared_libraries
+ else:
+ files = target.files.to_list()
+ for f in files:
+ uses_shared_libraries = cc_helper.is_valid_shared_library_artifact(f)
+ if uses_shared_libraries:
+ break
+ if uses_shared_libraries:
+ break
+
+ py_info_kwargs = dict(
+ transitive_sources = depset(
+ transitive = [deps_transitive_sources, direct_sources],
+ ),
+ imports = imports,
+ # NOTE: This isn't strictly correct, but with Python 2 gone,
+ # the srcs_version logic is largely defunct, so shouldn't matter in
+ # practice.
+ has_py2_only_sources = has_py2_only_sources,
+ has_py3_only_sources = has_py3_only_sources,
+ uses_shared_libraries = uses_shared_libraries,
+ )
+
+ # TODO(b/203567235): Set `uses_shared_libraries` field, though the Bazel
+ # docs indicate it's unused in Bazel and may be removed.
+ py_info = PyInfo(**py_info_kwargs)
+ builtin_py_info = BuiltinPyInfo(**py_info_kwargs)
+
+ return py_info, deps_transitive_sources, builtin_py_info
+
+def _get_py_info(target):
+ return target[PyInfo] if PyInfo in target else target[BuiltinPyInfo]
+
+def create_instrumented_files_info(ctx):
+ return _coverage_common.instrumented_files_info(
+ ctx,
+ source_attributes = ["srcs"],
+ dependency_attributes = ["deps", "data"],
+ extensions = _PYTHON_SOURCE_EXTENSIONS,
+ )
+
+def create_output_group_info(transitive_sources, extra_groups):
+ return OutputGroupInfo(
+ compilation_prerequisites_INTERNAL_ = transitive_sources,
+ compilation_outputs = transitive_sources,
+ **extra_groups
+ )
+
+def maybe_add_test_execution_info(providers, ctx):
+ """Adds ExecutionInfo, if necessary for proper test execution.
+
+ Args:
+ providers: Mutable list of providers; may have ExecutionInfo
+ provider appended.
+ ctx: Rule ctx.
+ """
+
+ # When built for Apple platforms, require the execution to be on a Mac.
+ # TODO(b/176993122): Remove when bazel automatically knows to run on darwin.
+ if target_platform_has_any_constraint(ctx, ctx.attr._apple_constraints):
+ providers.append(_testing.ExecutionInfo({"requires-darwin": ""}))
+
+_BOOL_TYPE = type(True)
+
+def is_bool(v):
+ return type(v) == _BOOL_TYPE
+
+def target_platform_has_any_constraint(ctx, constraints):
+ """Check if target platform has any of a list of constraints.
+
+ Args:
+ ctx: rule context.
+ constraints: label_list of constraints.
+
+ Returns:
+ True if target platform has at least one of the constraints.
+ """
+ for constraint in constraints:
+ constraint_value = constraint[_platform_common.ConstraintValueInfo]
+ if ctx.target_platform_has_constraint(constraint_value):
+ return True
+ return False
+
+def check_native_allowed(ctx):
+ """Check if the usage of the native rule is allowed.
+
+ Args:
+ ctx: rule context to check
+ """
+ if not ctx.fragments.py.disallow_native_rules:
+ return
+
+ if _MIGRATION_TAG in ctx.attr.tags:
+ return
+
+ # NOTE: The main repo name is empty in *labels*, but not in
+ # ctx.workspace_name
+ is_main_repo = not bool(ctx.label.workspace_name)
+ if is_main_repo:
+ check_label = ctx.label
+ else:
+ # package_group doesn't allow @repo syntax, so we work around that
+ # by prefixing external repos with a fake package path. This also
+ # makes it easy to enable or disable all external repos.
+ check_label = Label("@//__EXTERNAL_REPOS__/{workspace}/{package}".format(
+ workspace = ctx.label.workspace_name,
+ package = ctx.label.package,
+ ))
+ allowlist = ctx.attr._native_rules_allowlist
+ if allowlist:
+ allowed = ctx.attr._native_rules_allowlist[PackageSpecificationInfo].contains(check_label)
+ allowlist_help = str(allowlist.label).replace("@//", "//")
+ else:
+ allowed = False
+ allowlist_help = ("no allowlist specified; all disallowed; specify one " +
+ "with --python_native_rules_allowlist")
+ if not allowed:
+ if ctx.attr.generator_function:
+ generator = "{generator_function}(name={generator_name}) in {generator_location}".format(
+ generator_function = ctx.attr.generator_function,
+ generator_name = ctx.attr.generator_name,
+ generator_location = ctx.attr.generator_location,
+ )
+ else:
+ generator = "No generator (called directly in BUILD file)"
+
+ msg = (
+ "{target} not allowed to use native.{rule}\n" +
+ "Generated by: {generator}\n" +
+ "Allowlist: {allowlist}\n" +
+ "Migrate to using @rules_python, see {help_url}\n" +
+ "FIXCMD: {fix_cmd} --target={target} --rule={rule} " +
+ "--generator_name={generator_name} --location={generator_location}"
+ )
+ fail(msg.format(
+ target = str(ctx.label).replace("@//", "//"),
+ rule = _py_builtins.get_rule_name(ctx),
+ generator = generator,
+ allowlist = allowlist_help,
+ generator_name = ctx.attr.generator_name,
+ generator_location = ctx.attr.generator_location,
+ help_url = NATIVE_RULES_MIGRATION_HELP_URL,
+ fix_cmd = NATIVE_RULES_MIGRATION_FIX_CMD,
+ ))
diff --git a/python/private/common/common_bazel.bzl b/python/private/common/common_bazel.bzl
new file mode 100644
index 0000000..7277337
--- /dev/null
+++ b/python/private/common/common_bazel.bzl
@@ -0,0 +1,109 @@
+# 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.
+"""Common functions that are specific to Bazel rule implementation"""
+
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load(":common.bzl", "is_bool")
+load(":providers.bzl", "PyCcLinkParamsProvider")
+load(":py_internal.bzl", "py_internal")
+
+# TODO: Load cc_common from rules_cc
+_cc_common = cc_common
+
+# TODO: Load CcInfo from rules_cc
+_CcInfo = CcInfo
+
+_py_builtins = py_internal
+
+def collect_cc_info(ctx, extra_deps = []):
+ """Collect C++ information from dependencies for Bazel.
+
+ Args:
+ ctx: Rule ctx; must have `deps` attribute.
+ extra_deps: list of Target to also collect C+ information from.
+
+ Returns:
+ CcInfo provider of merged information.
+ """
+ deps = ctx.attr.deps
+ if extra_deps:
+ deps = list(deps)
+ deps.extend(extra_deps)
+ cc_infos = []
+ for dep in deps:
+ if _CcInfo in dep:
+ cc_infos.append(dep[_CcInfo])
+
+ if PyCcLinkParamsProvider in dep:
+ cc_infos.append(dep[PyCcLinkParamsProvider].cc_info)
+
+ return _cc_common.merge_cc_infos(cc_infos = cc_infos)
+
+def maybe_precompile(ctx, srcs):
+ """Computes all the outputs (maybe precompiled) from the input srcs.
+
+ See create_binary_semantics_struct for details about this function.
+
+ Args:
+ ctx: Rule ctx.
+ srcs: List of Files; the inputs to maybe precompile.
+
+ Returns:
+ List of Files; the desired output files derived from the input sources.
+ """
+ _ = ctx # @unused
+
+ # Precompilation isn't implemented yet, so just return srcs as-is
+ return srcs
+
+def get_imports(ctx):
+ """Gets the imports from a rule's `imports` attribute.
+
+ See create_binary_semantics_struct for details about this function.
+
+ Args:
+ ctx: Rule ctx.
+
+ Returns:
+ List of strings.
+ """
+ prefix = "{}/{}".format(
+ ctx.workspace_name,
+ _py_builtins.get_label_repo_runfiles_path(ctx.label),
+ )
+ result = []
+ for import_str in ctx.attr.imports:
+ import_str = ctx.expand_make_variables("imports", import_str, {})
+ if import_str.startswith("/"):
+ continue
+
+ # To prevent "escaping" out of the runfiles tree, we normalize
+ # the path and ensure it doesn't have up-level references.
+ import_path = paths.normalize("{}/{}".format(prefix, import_str))
+ if import_path.startswith("../") or import_path == "..":
+ fail("Path '{}' references a path above the execution root".format(
+ import_str,
+ ))
+ result.append(import_path)
+ return result
+
+def convert_legacy_create_init_to_int(kwargs):
+ """Convert "legacy_create_init" key to int, in-place.
+
+ Args:
+ kwargs: The kwargs to modify. The key "legacy_create_init", if present
+ and bool, will be converted to its integer value, in place.
+ """
+ if is_bool(kwargs.get("legacy_create_init")):
+ kwargs["legacy_create_init"] = 1 if kwargs["legacy_create_init"] else 0
diff --git a/python/private/common/providers.bzl b/python/private/common/providers.bzl
new file mode 100644
index 0000000..38a7054
--- /dev/null
+++ b/python/private/common/providers.bzl
@@ -0,0 +1,224 @@
+# 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.
+"""Providers for Python rules."""
+
+load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER")
+
+# TODO: load CcInfo from rules_cc
+_CcInfo = CcInfo
+
+DEFAULT_STUB_SHEBANG = "#!/usr/bin/env python3"
+
+DEFAULT_BOOTSTRAP_TEMPLATE = Label("//python/private:python_bootstrap_template.txt")
+
+_PYTHON_VERSION_VALUES = ["PY2", "PY3"]
+
+# Helper to make the provider definitions not crash under Bazel 5.4:
+# Bazel 5.4 doesn't support the `init` arg of `provider()`, so we have to
+# not pass that when using Bazel 5.4. But, not passing the `init` arg
+# changes the return value from a two-tuple to a single value, which then
+# breaks Bazel 6+ code.
+# This isn't actually used under Bazel 5.4, so just stub out the values
+# to get past the loading phase.
+def _define_provider(doc, fields, **kwargs):
+ if not IS_BAZEL_6_OR_HIGHER:
+ return provider("Stub, not used", fields = []), None
+ return provider(doc = doc, fields = fields, **kwargs)
+
+def _PyRuntimeInfo_init(
+ *,
+ interpreter_path = None,
+ interpreter = None,
+ files = None,
+ coverage_tool = None,
+ coverage_files = None,
+ python_version,
+ stub_shebang = None,
+ bootstrap_template = None):
+ if (interpreter_path and interpreter) or (not interpreter_path and not interpreter):
+ fail("exactly one of interpreter or interpreter_path must be specified")
+
+ if interpreter_path and files != None:
+ fail("cannot specify 'files' if 'interpreter_path' is given")
+
+ if (coverage_tool and not coverage_files) or (not coverage_tool and coverage_files):
+ fail(
+ "coverage_tool and coverage_files must both be set or neither must be set, " +
+ "got coverage_tool={}, coverage_files={}".format(
+ coverage_tool,
+ coverage_files,
+ ),
+ )
+
+ if python_version not in _PYTHON_VERSION_VALUES:
+ fail("invalid python_version: '{}'; must be one of {}".format(
+ python_version,
+ _PYTHON_VERSION_VALUES,
+ ))
+
+ if files != None and type(files) != type(depset()):
+ fail("invalid files: got value of type {}, want depset".format(type(files)))
+
+ if interpreter:
+ if files == None:
+ files = depset()
+ else:
+ files = None
+
+ if coverage_files == None:
+ coverage_files = depset()
+
+ if not stub_shebang:
+ stub_shebang = DEFAULT_STUB_SHEBANG
+
+ return {
+ "bootstrap_template": bootstrap_template,
+ "coverage_files": coverage_files,
+ "coverage_tool": coverage_tool,
+ "files": files,
+ "interpreter": interpreter,
+ "interpreter_path": interpreter_path,
+ "python_version": python_version,
+ "stub_shebang": stub_shebang,
+ }
+
+# TODO(#15897): Rename this to PyRuntimeInfo when we're ready to replace the Java
+# implemented provider with the Starlark one.
+PyRuntimeInfo, _unused_raw_py_runtime_info_ctor = _define_provider(
+ doc = """Contains information about a Python runtime, as returned by the `py_runtime`
+rule.
+
+A Python runtime describes either a *platform runtime* or an *in-build runtime*.
+A platform runtime accesses a system-installed interpreter at a known path,
+whereas an in-build runtime points to a `File` that acts as the interpreter. In
+both cases, an "interpreter" is really any executable binary or wrapper script
+that is capable of running a Python script passed on the command line, following
+the same conventions as the standard CPython interpreter.
+""",
+ init = _PyRuntimeInfo_init,
+ fields = {
+ "bootstrap_template": (
+ "See py_runtime_rule.bzl%py_runtime.bootstrap_template for docs."
+ ),
+ "coverage_files": (
+ "The files required at runtime for using `coverage_tool`. " +
+ "Will be `None` if no `coverage_tool` was provided."
+ ),
+ "coverage_tool": (
+ "If set, this field is a `File` representing tool used for collecting code coverage information from python tests. Otherwise, this is `None`."
+ ),
+ "files": (
+ "If this is an in-build runtime, this field is a `depset` of `File`s" +
+ "that need to be added to the runfiles of an executable target that " +
+ "uses this runtime (in particular, files needed by `interpreter`). " +
+ "The value of `interpreter` need not be included in this field. If " +
+ "this is a platform runtime then this field is `None`."
+ ),
+ "interpreter": (
+ "If this is an in-build runtime, this field is a `File` representing " +
+ "the interpreter. Otherwise, this is `None`. Note that an in-build " +
+ "runtime can use either a prebuilt, checked-in interpreter or an " +
+ "interpreter built from source."
+ ),
+ "interpreter_path": (
+ "If this is a platform runtime, this field is the absolute " +
+ "filesystem path to the interpreter on the target platform. " +
+ "Otherwise, this is `None`."
+ ),
+ "python_version": (
+ "Indicates whether this runtime uses Python major version 2 or 3. " +
+ "Valid values are (only) `\"PY2\"` and " +
+ "`\"PY3\"`."
+ ),
+ "stub_shebang": (
+ "\"Shebang\" expression prepended to the bootstrapping Python stub " +
+ "script used when executing `py_binary` targets. Does not " +
+ "apply to Windows."
+ ),
+ },
+)
+
+def _check_arg_type(name, required_type, value):
+ value_type = type(value)
+ if value_type != required_type:
+ fail("parameter '{}' got value of type '{}', want '{}'".format(
+ name,
+ value_type,
+ required_type,
+ ))
+
+def _PyInfo_init(
+ *,
+ transitive_sources,
+ uses_shared_libraries = False,
+ imports = depset(),
+ has_py2_only_sources = False,
+ has_py3_only_sources = False):
+ _check_arg_type("transitive_sources", "depset", transitive_sources)
+
+ # Verify it's postorder compatible, but retain is original ordering.
+ depset(transitive = [transitive_sources], order = "postorder")
+
+ _check_arg_type("uses_shared_libraries", "bool", uses_shared_libraries)
+ _check_arg_type("imports", "depset", imports)
+ _check_arg_type("has_py2_only_sources", "bool", has_py2_only_sources)
+ _check_arg_type("has_py3_only_sources", "bool", has_py3_only_sources)
+ return {
+ "has_py2_only_sources": has_py2_only_sources,
+ "has_py3_only_sources": has_py2_only_sources,
+ "imports": imports,
+ "transitive_sources": transitive_sources,
+ "uses_shared_libraries": uses_shared_libraries,
+ }
+
+PyInfo, _unused_raw_py_info_ctor = _define_provider(
+ doc = "Encapsulates information provided by the Python rules.",
+ init = _PyInfo_init,
+ fields = {
+ "has_py2_only_sources": "Whether any of this target's transitive sources requires a Python 2 runtime.",
+ "has_py3_only_sources": "Whether any of this target's transitive sources requires a Python 3 runtime.",
+ "imports": """\
+A depset of import path strings to be added to the `PYTHONPATH` of executable
+Python targets. These are accumulated from the transitive `deps`.
+The order of the depset is not guaranteed and may be changed in the future. It
+is recommended to use `default` order (the default).
+""",
+ "transitive_sources": """\
+A (`postorder`-compatible) depset of `.py` files appearing in the target's
+`srcs` and the `srcs` of the target's transitive `deps`.
+""",
+ "uses_shared_libraries": """
+Whether any of this target's transitive `deps` has a shared library file (such
+as a `.so` file).
+
+This field is currently unused in Bazel and may go away in the future.
+""",
+ },
+)
+
+def _PyCcLinkParamsProvider_init(cc_info):
+ return {
+ "cc_info": _CcInfo(linking_context = cc_info.linking_context),
+ }
+
+# buildifier: disable=name-conventions
+PyCcLinkParamsProvider, _unused_raw_py_cc_link_params_provider_ctor = _define_provider(
+ doc = ("Python-wrapper to forward CcInfo.linking_context. This is to " +
+ "allow Python targets to propagate C++ linking information, but " +
+ "without the Python target appearing to be a valid C++ rule dependency"),
+ init = _PyCcLinkParamsProvider_init,
+ fields = {
+ "cc_info": "A CcInfo instance; it has only linking_context set",
+ },
+)
diff --git a/python/private/common/py_binary_macro_bazel.bzl b/python/private/common/py_binary_macro_bazel.bzl
new file mode 100644
index 0000000..a6c4e97
--- /dev/null
+++ b/python/private/common/py_binary_macro_bazel.bzl
@@ -0,0 +1,21 @@
+# 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.
+"""Implementation of macro-half of py_binary rule."""
+
+load(":common_bazel.bzl", "convert_legacy_create_init_to_int")
+load(":py_binary_rule_bazel.bzl", py_binary_rule = "py_binary")
+
+def py_binary(**kwargs):
+ convert_legacy_create_init_to_int(kwargs)
+ py_binary_rule(**kwargs)
diff --git a/python/private/common/py_binary_rule_bazel.bzl b/python/private/common/py_binary_rule_bazel.bzl
new file mode 100644
index 0000000..9ce0726
--- /dev/null
+++ b/python/private/common/py_binary_rule_bazel.bzl
@@ -0,0 +1,52 @@
+# 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.
+"""Rule implementation of py_binary for Bazel."""
+
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load(":attributes.bzl", "AGNOSTIC_BINARY_ATTRS")
+load(
+ ":py_executable_bazel.bzl",
+ "create_executable_rule",
+ "py_executable_bazel_impl",
+)
+
+_PY_TEST_ATTRS = {
+ # Magic attribute to help C++ coverage work. There's no
+ # docs about this; see TestActionBuilder.java
+ "_collect_cc_coverage": attr.label(
+ default = "@bazel_tools//tools/test:collect_cc_coverage",
+ executable = True,
+ cfg = "exec",
+ ),
+ # Magic attribute to make coverage work. There's no
+ # docs about this; see TestActionBuilder.java
+ "_lcov_merger": attr.label(
+ default = configuration_field(fragment = "coverage", name = "output_generator"),
+ executable = True,
+ cfg = "exec",
+ ),
+}
+
+def _py_binary_impl(ctx):
+ return py_executable_bazel_impl(
+ ctx = ctx,
+ is_test = False,
+ inherited_environment = [],
+ )
+
+py_binary = create_executable_rule(
+ implementation = _py_binary_impl,
+ attrs = dicts.add(AGNOSTIC_BINARY_ATTRS, _PY_TEST_ATTRS),
+ executable = True,
+)
diff --git a/python/private/common/py_executable.bzl b/python/private/common/py_executable.bzl
new file mode 100644
index 0000000..a24bad6
--- /dev/null
+++ b/python/private/common/py_executable.bzl
@@ -0,0 +1,860 @@
+# 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.
+"""Common functionality between test/binary executables."""
+
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load(
+ ":attributes.bzl",
+ "AGNOSTIC_EXECUTABLE_ATTRS",
+ "COMMON_ATTRS",
+ "PY_SRCS_ATTRS",
+ "SRCS_VERSION_ALL_VALUES",
+ "create_srcs_attr",
+ "create_srcs_version_attr",
+)
+load(":cc_helper.bzl", "cc_helper")
+load(
+ ":common.bzl",
+ "TOOLCHAIN_TYPE",
+ "check_native_allowed",
+ "collect_imports",
+ "collect_runfiles",
+ "create_instrumented_files_info",
+ "create_output_group_info",
+ "create_py_info",
+ "csv",
+ "filter_to_py_srcs",
+ "target_platform_has_any_constraint",
+ "union_attrs",
+)
+load(
+ ":providers.bzl",
+ "PyCcLinkParamsProvider",
+ "PyRuntimeInfo",
+)
+load(":py_internal.bzl", "py_internal")
+load(
+ ":semantics.bzl",
+ "ALLOWED_MAIN_EXTENSIONS",
+ "BUILD_DATA_SYMLINK_PATH",
+ "IS_BAZEL",
+ "PY_RUNTIME_ATTR_NAME",
+)
+
+# TODO: Load cc_common from rules_cc
+_cc_common = cc_common
+
+_py_builtins = py_internal
+
+# Bazel 5.4 doesn't have config_common.toolchain_type
+_CC_TOOLCHAINS = [config_common.toolchain_type(
+ "@bazel_tools//tools/cpp:toolchain_type",
+ mandatory = False,
+)] if hasattr(config_common, "toolchain_type") else []
+
+# Non-Google-specific attributes for executables
+# These attributes are for rules that accept Python sources.
+EXECUTABLE_ATTRS = union_attrs(
+ COMMON_ATTRS,
+ AGNOSTIC_EXECUTABLE_ATTRS,
+ PY_SRCS_ATTRS,
+ {
+ # TODO(b/203567235): In the Java impl, any file is allowed. While marked
+ # label, it is more treated as a string, and doesn't have to refer to
+ # anything that exists because it gets treated as suffix-search string
+ # over `srcs`.
+ "main": attr.label(
+ allow_single_file = True,
+ doc = """\
+Optional; the name of the source file that is the main entry point of the
+application. This file must also be listed in `srcs`. If left unspecified,
+`name`, with `.py` appended, is used instead. If `name` does not match any
+filename in `srcs`, `main` must be specified.
+""",
+ ),
+ # TODO(b/203567235): In Google, this attribute is deprecated, and can
+ # only effectively be PY3. Externally, with Bazel, this attribute has
+ # a separate story.
+ "python_version": attr.string(
+ # TODO(b/203567235): In the Java impl, the default comes from
+ # --python_version. Not clear what the Starlark equivalent is.
+ default = "PY3",
+ # NOTE: Some tests care about the order of these values.
+ values = ["PY2", "PY3"],
+ ),
+ "_windows_constraints": attr.label_list(
+ default = [
+ "@platforms//os:windows",
+ ],
+ ),
+ },
+ create_srcs_version_attr(values = SRCS_VERSION_ALL_VALUES),
+ create_srcs_attr(mandatory = True),
+ allow_none = True,
+)
+
+def py_executable_base_impl(ctx, *, semantics, is_test, inherited_environment = []):
+ """Base rule implementation for a Python executable.
+
+ Google and Bazel call this common base and apply customizations using the
+ semantics object.
+
+ Args:
+ ctx: The rule ctx
+ semantics: BinarySemantics struct; see create_binary_semantics_struct()
+ is_test: bool, True if the rule is a test rule (has `test=True`),
+ False if not (has `executable=True`)
+ inherited_environment: List of str; additional environment variable
+ names that should be inherited from the runtime environment when the
+ executable is run.
+ Returns:
+ DefaultInfo provider for the executable
+ """
+ _validate_executable(ctx)
+
+ main_py = determine_main(ctx)
+ direct_sources = filter_to_py_srcs(ctx.files.srcs)
+ output_sources = semantics.maybe_precompile(ctx, direct_sources)
+ imports = collect_imports(ctx, semantics)
+ executable, files_to_build = _compute_outputs(ctx, output_sources)
+
+ runtime_details = _get_runtime_details(ctx, semantics)
+ if ctx.configuration.coverage_enabled:
+ extra_deps = semantics.get_coverage_deps(ctx, runtime_details)
+ else:
+ extra_deps = []
+
+ # The debugger dependency should be prevented by select() config elsewhere,
+ # but just to be safe, also guard against adding it to the output here.
+ if not _is_tool_config(ctx):
+ extra_deps.extend(semantics.get_debugger_deps(ctx, runtime_details))
+
+ cc_details = semantics.get_cc_details_for_binary(ctx, extra_deps = extra_deps)
+ native_deps_details = _get_native_deps_details(
+ ctx,
+ semantics = semantics,
+ cc_details = cc_details,
+ is_test = is_test,
+ )
+ runfiles_details = _get_base_runfiles_for_binary(
+ ctx,
+ executable = executable,
+ extra_deps = extra_deps,
+ files_to_build = files_to_build,
+ extra_common_runfiles = [
+ runtime_details.runfiles,
+ cc_details.extra_runfiles,
+ native_deps_details.runfiles,
+ semantics.get_extra_common_runfiles_for_binary(ctx),
+ ],
+ semantics = semantics,
+ )
+ exec_result = semantics.create_executable(
+ ctx,
+ executable = executable,
+ main_py = main_py,
+ imports = imports,
+ is_test = is_test,
+ runtime_details = runtime_details,
+ cc_details = cc_details,
+ native_deps_details = native_deps_details,
+ runfiles_details = runfiles_details,
+ )
+ files_to_build = depset(transitive = [
+ exec_result.extra_files_to_build,
+ files_to_build,
+ ])
+ extra_exec_runfiles = ctx.runfiles(transitive_files = files_to_build)
+ runfiles_details = struct(
+ default_runfiles = runfiles_details.default_runfiles.merge(extra_exec_runfiles),
+ data_runfiles = runfiles_details.data_runfiles.merge(extra_exec_runfiles),
+ )
+
+ legacy_providers, modern_providers = _create_providers(
+ ctx = ctx,
+ executable = executable,
+ runfiles_details = runfiles_details,
+ main_py = main_py,
+ imports = imports,
+ direct_sources = direct_sources,
+ files_to_build = files_to_build,
+ runtime_details = runtime_details,
+ cc_info = cc_details.cc_info_for_propagating,
+ inherited_environment = inherited_environment,
+ semantics = semantics,
+ output_groups = exec_result.output_groups,
+ )
+ return struct(
+ legacy_providers = legacy_providers,
+ providers = modern_providers,
+ )
+
+def _validate_executable(ctx):
+ if ctx.attr.python_version != "PY3":
+ fail("It is not allowed to use Python 2")
+ check_native_allowed(ctx)
+
+def _compute_outputs(ctx, output_sources):
+ if target_platform_has_any_constraint(ctx, ctx.attr._windows_constraints):
+ executable = ctx.actions.declare_file(ctx.label.name + ".exe")
+ else:
+ executable = ctx.actions.declare_file(ctx.label.name)
+
+ # TODO(b/208657718): Remove output_sources from the default outputs
+ # once the depot is cleaned up.
+ return executable, depset([executable] + output_sources)
+
+def _get_runtime_details(ctx, semantics):
+ """Gets various information about the Python runtime to use.
+
+ While most information comes from the toolchain, various legacy and
+ compatibility behaviors require computing some other information.
+
+ Args:
+ ctx: Rule ctx
+ semantics: A `BinarySemantics` struct; see `create_binary_semantics_struct`
+
+ Returns:
+ A struct; see inline-field comments of the return value for details.
+ """
+
+ # Bazel has --python_path. This flag has a computed default of "python" when
+ # its actual default is null (see
+ # BazelPythonConfiguration.java#getPythonPath). This flag is only used if
+ # toolchains are not enabled and `--python_top` isn't set. Note that Google
+ # used to have a variant of this named --python_binary, but it has since
+ # been removed.
+ #
+ # TOOD(bazelbuild/bazel#7901): Remove this once --python_path flag is removed.
+
+ if IS_BAZEL:
+ flag_interpreter_path = ctx.fragments.bazel_py.python_path
+ toolchain_runtime, effective_runtime = _maybe_get_runtime_from_ctx(ctx)
+ if not effective_runtime:
+ # Clear these just in case
+ toolchain_runtime = None
+ effective_runtime = None
+
+ else: # Google code path
+ flag_interpreter_path = None
+ toolchain_runtime, effective_runtime = _maybe_get_runtime_from_ctx(ctx)
+ if not effective_runtime:
+ fail("Unable to find Python runtime")
+
+ if effective_runtime:
+ direct = [] # List of files
+ transitive = [] # List of depsets
+ if effective_runtime.interpreter:
+ direct.append(effective_runtime.interpreter)
+ transitive.append(effective_runtime.files)
+
+ if ctx.configuration.coverage_enabled:
+ if effective_runtime.coverage_tool:
+ direct.append(effective_runtime.coverage_tool)
+ if effective_runtime.coverage_files:
+ transitive.append(effective_runtime.coverage_files)
+ runtime_files = depset(direct = direct, transitive = transitive)
+ else:
+ runtime_files = depset()
+
+ executable_interpreter_path = semantics.get_interpreter_path(
+ ctx,
+ runtime = effective_runtime,
+ flag_interpreter_path = flag_interpreter_path,
+ )
+
+ return struct(
+ # Optional PyRuntimeInfo: The runtime found from toolchain resolution.
+ # This may be None because, within Google, toolchain resolution isn't
+ # yet enabled.
+ toolchain_runtime = toolchain_runtime,
+ # Optional PyRuntimeInfo: The runtime that should be used. When
+ # toolchain resolution is enabled, this is the same as
+ # `toolchain_resolution`. Otherwise, this probably came from the
+ # `_python_top` attribute that the Google implementation still uses.
+ # This is separate from `toolchain_runtime` because toolchain_runtime
+ # is propagated as a provider, while non-toolchain runtimes are not.
+ effective_runtime = effective_runtime,
+ # str; Path to the Python interpreter to use for running the executable
+ # itself (not the bootstrap script). Either an absolute path (which
+ # means it is platform-specific), or a runfiles-relative path (which
+ # means the interpreter should be within `runtime_files`)
+ executable_interpreter_path = executable_interpreter_path,
+ # runfiles: Additional runfiles specific to the runtime that should
+ # be included. For in-build runtimes, this shold include the interpreter
+ # and any supporting files.
+ runfiles = ctx.runfiles(transitive_files = runtime_files),
+ )
+
+def _maybe_get_runtime_from_ctx(ctx):
+ """Finds the PyRuntimeInfo from the toolchain or attribute, if available.
+
+ Returns:
+ 2-tuple of toolchain_runtime, effective_runtime
+ """
+ if ctx.fragments.py.use_toolchains:
+ toolchain = ctx.toolchains[TOOLCHAIN_TYPE]
+
+ if not hasattr(toolchain, "py3_runtime"):
+ fail("Python toolchain field 'py3_runtime' is missing")
+ if not toolchain.py3_runtime:
+ fail("Python toolchain missing py3_runtime")
+ py3_runtime = toolchain.py3_runtime
+
+ # Hack around the fact that the autodetecting Python toolchain, which is
+ # automatically registered, does not yet support Windows. In this case,
+ # we want to return null so that _get_interpreter_path falls back on
+ # --python_path. See tools/python/toolchain.bzl.
+ # TODO(#7844): Remove this hack when the autodetecting toolchain has a
+ # Windows implementation.
+ if py3_runtime.interpreter_path == "/_magic_pyruntime_sentinel_do_not_use":
+ return None, None
+
+ if py3_runtime.python_version != "PY3":
+ fail("Python toolchain py3_runtime must be python_version=PY3, got {}".format(
+ py3_runtime.python_version,
+ ))
+ toolchain_runtime = toolchain.py3_runtime
+ effective_runtime = toolchain_runtime
+ else:
+ toolchain_runtime = None
+ attr_target = getattr(ctx.attr, PY_RUNTIME_ATTR_NAME)
+
+ # In Bazel, --python_top is null by default.
+ if attr_target and PyRuntimeInfo in attr_target:
+ effective_runtime = attr_target[PyRuntimeInfo]
+ else:
+ return None, None
+
+ return toolchain_runtime, effective_runtime
+
+def _get_base_runfiles_for_binary(
+ ctx,
+ *,
+ executable,
+ extra_deps,
+ files_to_build,
+ extra_common_runfiles,
+ semantics):
+ """Returns the set of runfiles necessary prior to executable creation.
+
+ NOTE: The term "common runfiles" refers to the runfiles that both the
+ default and data runfiles have in common.
+
+ Args:
+ ctx: The rule ctx.
+ executable: The main executable output.
+ extra_deps: List of Targets; additional targets whose runfiles
+ will be added to the common runfiles.
+ files_to_build: depset of File of the default outputs to add into runfiles.
+ extra_common_runfiles: List of runfiles; additional runfiles that
+ will be added to the common runfiles.
+ semantics: A `BinarySemantics` struct; see `create_binary_semantics_struct`.
+
+ Returns:
+ struct with attributes:
+ * default_runfiles: The default runfiles
+ * data_runfiles: The data runfiles
+ """
+ common_runfiles = collect_runfiles(ctx, depset(
+ direct = [executable],
+ transitive = [files_to_build],
+ ))
+ if extra_deps:
+ common_runfiles = common_runfiles.merge_all([
+ t[DefaultInfo].default_runfiles
+ for t in extra_deps
+ ])
+ common_runfiles = common_runfiles.merge_all(extra_common_runfiles)
+
+ if semantics.should_create_init_files(ctx):
+ common_runfiles = _py_builtins.merge_runfiles_with_generated_inits_empty_files_supplier(
+ ctx = ctx,
+ runfiles = common_runfiles,
+ )
+
+ # Don't include build_data.txt in data runfiles. This allows binaries to
+ # contain other binaries while still using the same fixed location symlink
+ # for the build_data.txt file. Really, the fixed location symlink should be
+ # removed and another way found to locate the underlying build data file.
+ data_runfiles = common_runfiles
+
+ if is_stamping_enabled(ctx, semantics) and semantics.should_include_build_data(ctx):
+ default_runfiles = common_runfiles.merge(_create_runfiles_with_build_data(
+ ctx,
+ semantics.get_central_uncachable_version_file(ctx),
+ semantics.get_extra_write_build_data_env(ctx),
+ ))
+ else:
+ default_runfiles = common_runfiles
+
+ return struct(
+ default_runfiles = default_runfiles,
+ data_runfiles = data_runfiles,
+ )
+
+def _create_runfiles_with_build_data(
+ ctx,
+ central_uncachable_version_file,
+ extra_write_build_data_env):
+ return ctx.runfiles(
+ symlinks = {
+ BUILD_DATA_SYMLINK_PATH: _write_build_data(
+ ctx,
+ central_uncachable_version_file,
+ extra_write_build_data_env,
+ ),
+ },
+ )
+
+def _write_build_data(ctx, central_uncachable_version_file, extra_write_build_data_env):
+ # TODO: Remove this logic when a central file is always available
+ if not central_uncachable_version_file:
+ version_file = ctx.actions.declare_file(ctx.label.name + "-uncachable_version_file.txt")
+ _py_builtins.copy_without_caching(
+ ctx = ctx,
+ read_from = ctx.version_file,
+ write_to = version_file,
+ )
+ else:
+ version_file = central_uncachable_version_file
+
+ direct_inputs = [ctx.info_file, version_file]
+
+ # A "constant metadata" file is basically a special file that doesn't
+ # support change detection logic and reports that it is unchanged. i.e., it
+ # behaves like ctx.version_file and is ignored when computing "what inputs
+ # changed" (see https://bazel.build/docs/user-manual#workspace-status).
+ #
+ # We do this so that consumers of the final build data file don't have
+ # to transitively rebuild everything -- the `uncachable_version_file` file
+ # isn't cachable, which causes the build data action to always re-run.
+ #
+ # While this technically means a binary could have stale build info,
+ # it ends up not mattering in practice because the volatile information
+ # doesn't meaningfully effect other outputs.
+ #
+ # This is also done for performance and Make It work reasons:
+ # * Passing the transitive dependencies into the action requires passing
+ # the runfiles, but actions don't directly accept runfiles. While
+ # flattening the depsets can be deferred, accessing the
+ # `runfiles.empty_filenames` attribute will will invoke the empty
+ # file supplier a second time, which is too much of a memory and CPU
+ # performance hit.
+ # * Some targets specify a directory in `data`, which is unsound, but
+ # mostly works. Google's RBE, unfortunately, rejects it.
+ # * A binary's transitive closure may be so large that it exceeds
+ # Google RBE limits for action inputs.
+ build_data = _py_builtins.declare_constant_metadata_file(
+ ctx = ctx,
+ name = ctx.label.name + ".build_data.txt",
+ root = ctx.bin_dir,
+ )
+
+ ctx.actions.run(
+ executable = ctx.executable._build_data_gen,
+ env = dicts.add({
+ # NOTE: ctx.info_file is undocumented; see
+ # https://github.com/bazelbuild/bazel/issues/9363
+ "INFO_FILE": ctx.info_file.path,
+ "OUTPUT": build_data.path,
+ "PLATFORM": cc_helper.find_cpp_toolchain(ctx).toolchain_id,
+ "TARGET": str(ctx.label),
+ "VERSION_FILE": version_file.path,
+ }, extra_write_build_data_env),
+ inputs = depset(
+ direct = direct_inputs,
+ ),
+ outputs = [build_data],
+ mnemonic = "PyWriteBuildData",
+ progress_message = "Generating %{label} build_data.txt",
+ )
+ return build_data
+
+def _get_native_deps_details(ctx, *, semantics, cc_details, is_test):
+ if not semantics.should_build_native_deps_dso(ctx):
+ return struct(dso = None, runfiles = ctx.runfiles())
+
+ cc_info = cc_details.cc_info_for_self_link
+
+ if not cc_info.linking_context.linker_inputs:
+ return struct(dso = None, runfiles = ctx.runfiles())
+
+ dso = ctx.actions.declare_file(semantics.get_native_deps_dso_name(ctx))
+ share_native_deps = py_internal.share_native_deps(ctx)
+ cc_feature_config = cc_configure_features(
+ ctx,
+ cc_toolchain = cc_details.cc_toolchain,
+ # See b/171276569#comment18: this feature string is just to allow
+ # Google's RBE to know the link action is for the Python case so it can
+ # take special actions (though as of Jun 2022, no special action is
+ # taken).
+ extra_features = ["native_deps_link"],
+ )
+ if share_native_deps:
+ linked_lib = _create_shared_native_deps_dso(
+ ctx,
+ cc_info = cc_info,
+ is_test = is_test,
+ requested_features = cc_feature_config.requested_features,
+ feature_configuration = cc_feature_config.feature_configuration,
+ )
+ ctx.actions.symlink(
+ output = dso,
+ target_file = linked_lib,
+ progress_message = "Symlinking shared native deps for %{label}",
+ )
+ else:
+ linked_lib = dso
+ _cc_common.link(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ linking_contexts = [cc_info.linking_context],
+ output_type = "dynamic_library",
+ never_link = True,
+ native_deps = True,
+ feature_configuration = cc_feature_config.feature_configuration,
+ cc_toolchain = cc_details.cc_toolchain,
+ test_only_target = is_test,
+ stamp = 1 if is_stamping_enabled(ctx, semantics) else 0,
+ main_output = linked_lib,
+ use_shareable_artifact_factory = True,
+ # NOTE: Only flags not captured by cc_info.linking_context need to
+ # be manually passed
+ user_link_flags = semantics.get_native_deps_user_link_flags(ctx),
+ )
+ return struct(
+ dso = dso,
+ runfiles = ctx.runfiles(files = [dso]),
+ )
+
+def _create_shared_native_deps_dso(
+ ctx,
+ *,
+ cc_info,
+ is_test,
+ feature_configuration,
+ requested_features):
+ linkstamps = cc_info.linking_context.linkstamps()
+
+ partially_disabled_thin_lto = (
+ _cc_common.is_enabled(
+ feature_name = "thin_lto_linkstatic_tests_use_shared_nonlto_backends",
+ feature_configuration = feature_configuration,
+ ) and not _cc_common.is_enabled(
+ feature_name = "thin_lto_all_linkstatic_use_shared_nonlto_backends",
+ feature_configuration = feature_configuration,
+ )
+ )
+ dso_hash = _get_shared_native_deps_hash(
+ linker_inputs = cc_helper.get_static_mode_params_for_dynamic_library_libraries(
+ depset([
+ lib
+ for linker_input in cc_info.linking_context.linker_inputs.to_list()
+ for lib in linker_input.libraries
+ ]),
+ ),
+ link_opts = [
+ flag
+ for input in cc_info.linking_context.linker_inputs.to_list()
+ for flag in input.user_link_flags
+ ],
+ linkstamps = [linkstamp.file() for linkstamp in linkstamps.to_list()],
+ build_info_artifacts = _cc_common.get_build_info(ctx) if linkstamps else [],
+ features = requested_features,
+ is_test_target_partially_disabled_thin_lto = is_test and partially_disabled_thin_lto,
+ )
+ return py_internal.declare_shareable_artifact(ctx, "_nativedeps/%x.so" % dso_hash)
+
+# This is a minimal version of NativeDepsHelper.getSharedNativeDepsPath, see
+# com.google.devtools.build.lib.rules.nativedeps.NativeDepsHelper#getSharedNativeDepsPath
+# The basic idea is to take all the inputs that affect linking and encode (via
+# hashing) them into the filename.
+# TODO(b/234232820): The settings that affect linking must be kept in sync with the actual
+# C++ link action. For more information, see the large descriptive comment on
+# NativeDepsHelper#getSharedNativeDepsPath.
+def _get_shared_native_deps_hash(
+ *,
+ linker_inputs,
+ link_opts,
+ linkstamps,
+ build_info_artifacts,
+ features,
+ is_test_target_partially_disabled_thin_lto):
+ # NOTE: We use short_path because the build configuration root in which
+ # files are always created already captures the configuration-specific
+ # parts, so no need to include them manually.
+ parts = []
+ for artifact in linker_inputs:
+ parts.append(artifact.short_path)
+ parts.append(str(len(link_opts)))
+ parts.extend(link_opts)
+ for artifact in linkstamps:
+ parts.append(artifact.short_path)
+ for artifact in build_info_artifacts:
+ parts.append(artifact.short_path)
+ parts.extend(sorted(features))
+
+ # Sharing of native dependencies may cause an {@link
+ # ActionConflictException} when ThinLTO is disabled for test and test-only
+ # targets that are statically linked, but enabled for other statically
+ # linked targets. This happens in case the artifacts for the shared native
+ # dependency are output by {@link Action}s owned by the non-test and test
+ # targets both. To fix this, we allow creation of multiple artifacts for the
+ # shared native library - one shared among the test and test-only targets
+ # where ThinLTO is disabled, and the other shared among other targets where
+ # ThinLTO is enabled. See b/138118275
+ parts.append("1" if is_test_target_partially_disabled_thin_lto else "0")
+
+ return hash("".join(parts))
+
+def determine_main(ctx):
+ """Determine the main entry point .py source file.
+
+ Args:
+ ctx: The rule ctx.
+
+ Returns:
+ Artifact; the main file. If one can't be found, an error is raised.
+ """
+ if ctx.attr.main:
+ proposed_main = ctx.attr.main.label.name
+ if not proposed_main.endswith(tuple(ALLOWED_MAIN_EXTENSIONS)):
+ fail("main must end in '.py'")
+ else:
+ if ctx.label.name.endswith(".py"):
+ fail("name must not end in '.py'")
+ proposed_main = ctx.label.name + ".py"
+
+ main_files = [src for src in ctx.files.srcs if _path_endswith(src.short_path, proposed_main)]
+ if not main_files:
+ if ctx.attr.main:
+ fail("could not find '{}' as specified by 'main' attribute".format(proposed_main))
+ else:
+ fail(("corresponding default '{}' does not appear in srcs. Add " +
+ "it or override default file name with a 'main' attribute").format(
+ proposed_main,
+ ))
+
+ elif len(main_files) > 1:
+ if ctx.attr.main:
+ fail(("file name '{}' specified by 'main' attributes matches multiple files. " +
+ "Matches: {}").format(
+ proposed_main,
+ csv([f.short_path for f in main_files]),
+ ))
+ else:
+ fail(("default main file '{}' matches multiple files in srcs. Perhaps specify " +
+ "an explicit file with 'main' attribute? Matches were: {}").format(
+ proposed_main,
+ csv([f.short_path for f in main_files]),
+ ))
+ return main_files[0]
+
+def _path_endswith(path, endswith):
+ # Use slash to anchor each path to prevent e.g.
+ # "ab/c.py".endswith("b/c.py") from incorrectly matching.
+ return ("/" + path).endswith("/" + endswith)
+
+def is_stamping_enabled(ctx, semantics):
+ """Tells if stamping is enabled or not.
+
+ Args:
+ ctx: The rule ctx
+ semantics: a semantics struct (see create_semantics_struct).
+ Returns:
+ bool; True if stamping is enabled, False if not.
+ """
+ if _is_tool_config(ctx):
+ return False
+
+ stamp = ctx.attr.stamp
+ if stamp == 1:
+ return True
+ elif stamp == 0:
+ return False
+ elif stamp == -1:
+ return semantics.get_stamp_flag(ctx)
+ else:
+ fail("Unsupported `stamp` value: {}".format(stamp))
+
+def _is_tool_config(ctx):
+ # NOTE: The is_tool_configuration() function is only usable by builtins.
+ # See https://github.com/bazelbuild/bazel/issues/14444 for the FR for
+ # a more public API. Until that's available, py_internal to the rescue.
+ return py_internal.is_tool_configuration(ctx)
+
+def _create_providers(
+ *,
+ ctx,
+ executable,
+ main_py,
+ direct_sources,
+ files_to_build,
+ runfiles_details,
+ imports,
+ cc_info,
+ inherited_environment,
+ runtime_details,
+ output_groups,
+ semantics):
+ """Creates the providers an executable should return.
+
+ Args:
+ ctx: The rule ctx.
+ executable: File; the target's executable file.
+ main_py: File; the main .py entry point.
+ direct_sources: list of Files; the direct, raw `.py` sources for the target.
+ This should only be Python source files. It should not include pyc
+ files.
+ files_to_build: depset of Files; the files for DefaultInfo.files
+ runfiles_details: runfiles that will become the default and data runfiles.
+ imports: depset of strings; the import paths to propagate
+ cc_info: optional CcInfo; Linking information to propagate as
+ PyCcLinkParamsProvider. Note that only the linking information
+ is propagated, not the whole CcInfo.
+ inherited_environment: list of strings; Environment variable names
+ that should be inherited from the environment the executuble
+ is run within.
+ runtime_details: struct of runtime information; see _get_runtime_details()
+ output_groups: dict[str, depset[File]]; used to create OutputGroupInfo
+ semantics: BinarySemantics struct; see create_binary_semantics()
+
+ Returns:
+ A two-tuple of:
+ 1. A dict of legacy providers.
+ 2. A list of modern providers.
+ """
+ providers = [
+ DefaultInfo(
+ executable = executable,
+ files = files_to_build,
+ default_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
+ ctx,
+ runfiles_details.default_runfiles,
+ ),
+ data_runfiles = _py_builtins.make_runfiles_respect_legacy_external_runfiles(
+ ctx,
+ runfiles_details.data_runfiles,
+ ),
+ ),
+ create_instrumented_files_info(ctx),
+ _create_run_environment_info(ctx, inherited_environment),
+ ]
+
+ # TODO(b/265840007): Make this non-conditional once Google enables
+ # --incompatible_use_python_toolchains.
+ if runtime_details.toolchain_runtime:
+ providers.append(runtime_details.toolchain_runtime)
+
+ # TODO(b/163083591): Remove the PyCcLinkParamsProvider once binaries-in-deps
+ # are cleaned up.
+ if cc_info:
+ providers.append(
+ PyCcLinkParamsProvider(cc_info = cc_info),
+ )
+
+ py_info, deps_transitive_sources, builtin_py_info = create_py_info(
+ ctx,
+ direct_sources = depset(direct_sources),
+ imports = imports,
+ )
+
+ # TODO(b/253059598): Remove support for extra actions; https://github.com/bazelbuild/bazel/issues/16455
+ listeners_enabled = _py_builtins.are_action_listeners_enabled(ctx)
+ if listeners_enabled:
+ _py_builtins.add_py_extra_pseudo_action(
+ ctx = ctx,
+ dependency_transitive_python_sources = deps_transitive_sources,
+ )
+
+ providers.append(py_info)
+ providers.append(builtin_py_info)
+ providers.append(create_output_group_info(py_info.transitive_sources, output_groups))
+
+ extra_legacy_providers, extra_providers = semantics.get_extra_providers(
+ ctx,
+ main_py = main_py,
+ runtime_details = runtime_details,
+ )
+ providers.extend(extra_providers)
+ return extra_legacy_providers, providers
+
+def _create_run_environment_info(ctx, inherited_environment):
+ expanded_env = {}
+ for key, value in ctx.attr.env.items():
+ expanded_env[key] = _py_builtins.expand_location_and_make_variables(
+ ctx = ctx,
+ attribute_name = "env[{}]".format(key),
+ expression = value,
+ targets = ctx.attr.data,
+ )
+ return RunEnvironmentInfo(
+ environment = expanded_env,
+ inherited_environment = inherited_environment,
+ )
+
+def create_base_executable_rule(*, attrs, fragments = [], **kwargs):
+ """Create a function for defining for Python binary/test targets.
+
+ Args:
+ attrs: Rule attributes
+ fragments: List of str; extra config fragments that are required.
+ **kwargs: Additional args to pass onto `rule()`
+
+ Returns:
+ A rule function
+ """
+ if "py" not in fragments:
+ # The list might be frozen, so use concatentation
+ fragments = fragments + ["py"]
+ return rule(
+ # TODO: add ability to remove attrs, i.e. for imports attr
+ attrs = dicts.add(EXECUTABLE_ATTRS, attrs),
+ toolchains = [TOOLCHAIN_TYPE] + _CC_TOOLCHAINS,
+ fragments = fragments,
+ **kwargs
+ )
+
+def cc_configure_features(ctx, *, cc_toolchain, extra_features):
+ """Configure C++ features for Python purposes.
+
+ Args:
+ ctx: Rule ctx
+ cc_toolchain: The CcToolchain the target is using.
+ extra_features: list of strings; additional features to request be
+ enabled.
+
+ Returns:
+ struct of the feature configuration and all requested features.
+ """
+ requested_features = ["static_linking_mode"]
+ requested_features.extend(extra_features)
+ requested_features.extend(ctx.features)
+ if "legacy_whole_archive" not in ctx.disabled_features:
+ requested_features.append("legacy_whole_archive")
+ feature_configuration = _cc_common.configure_features(
+ ctx = ctx,
+ cc_toolchain = cc_toolchain,
+ requested_features = requested_features,
+ unsupported_features = ctx.disabled_features,
+ )
+ return struct(
+ feature_configuration = feature_configuration,
+ requested_features = requested_features,
+ )
+
+only_exposed_for_google_internal_reason = struct(
+ create_runfiles_with_build_data = _create_runfiles_with_build_data,
+)
diff --git a/python/private/common/py_executable_bazel.bzl b/python/private/common/py_executable_bazel.bzl
new file mode 100644
index 0000000..ecdef9a
--- /dev/null
+++ b/python/private/common/py_executable_bazel.bzl
@@ -0,0 +1,483 @@
+# 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.
+"""Implementation for Bazel Python executable."""
+
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load(":attributes_bazel.bzl", "IMPORTS_ATTRS")
+load(
+ ":common.bzl",
+ "create_binary_semantics_struct",
+ "create_cc_details_struct",
+ "create_executable_result_struct",
+ "target_platform_has_any_constraint",
+ "union_attrs",
+)
+load(":common_bazel.bzl", "collect_cc_info", "get_imports", "maybe_precompile")
+load(":providers.bzl", "DEFAULT_STUB_SHEBANG")
+load(
+ ":py_executable.bzl",
+ "create_base_executable_rule",
+ "py_executable_base_impl",
+)
+load(":py_internal.bzl", "py_internal")
+
+_py_builtins = py_internal
+_EXTERNAL_PATH_PREFIX = "external"
+_ZIP_RUNFILES_DIRECTORY_NAME = "runfiles"
+
+BAZEL_EXECUTABLE_ATTRS = union_attrs(
+ IMPORTS_ATTRS,
+ {
+ "legacy_create_init": attr.int(
+ default = -1,
+ values = [-1, 0, 1],
+ doc = """\
+Whether to implicitly create empty `__init__.py` files in the runfiles tree.
+These are created in every directory containing Python source code or shared
+libraries, and every parent directory of those directories, excluding the repo
+root directory. The default, `-1` (auto), means true unless
+`--incompatible_default_to_explicit_init_py` is used. If false, the user is
+responsible for creating (possibly empty) `__init__.py` files and adding them to
+the `srcs` of Python targets as required.
+ """,
+ ),
+ "_bootstrap_template": attr.label(
+ allow_single_file = True,
+ default = "@bazel_tools//tools/python:python_bootstrap_template.txt",
+ ),
+ "_launcher": attr.label(
+ cfg = "target",
+ default = "@bazel_tools//tools/launcher:launcher",
+ executable = True,
+ ),
+ "_py_interpreter": attr.label(
+ # The configuration_field args are validated when called;
+ # we use the precense of py_internal to indicate this Bazel
+ # build has that fragment and name.
+ default = configuration_field(
+ fragment = "bazel_py",
+ name = "python_top",
+ ) if py_internal else None,
+ ),
+ # TODO: This appears to be vestigial. It's only added because
+ # GraphlessQueryTest.testLabelsOperator relies on it to test for
+ # query behavior of implicit dependencies.
+ "_py_toolchain_type": attr.label(
+ default = "@bazel_tools//tools/python:toolchain_type",
+ ),
+ "_windows_launcher_maker": attr.label(
+ default = "@bazel_tools//tools/launcher:launcher_maker",
+ cfg = "exec",
+ executable = True,
+ ),
+ "_zipper": attr.label(
+ cfg = "exec",
+ executable = True,
+ default = "@bazel_tools//tools/zip:zipper",
+ ),
+ },
+)
+
+def create_executable_rule(*, attrs, **kwargs):
+ return create_base_executable_rule(
+ attrs = dicts.add(BAZEL_EXECUTABLE_ATTRS, attrs),
+ fragments = ["py", "bazel_py"],
+ **kwargs
+ )
+
+def py_executable_bazel_impl(ctx, *, is_test, inherited_environment):
+ """Common code for executables for Baze."""
+ result = py_executable_base_impl(
+ ctx = ctx,
+ semantics = create_binary_semantics_bazel(),
+ is_test = is_test,
+ inherited_environment = inherited_environment,
+ )
+ return struct(
+ providers = result.providers,
+ **result.legacy_providers
+ )
+
+def create_binary_semantics_bazel():
+ return create_binary_semantics_struct(
+ # keep-sorted start
+ create_executable = _create_executable,
+ get_cc_details_for_binary = _get_cc_details_for_binary,
+ get_central_uncachable_version_file = lambda ctx: None,
+ get_coverage_deps = _get_coverage_deps,
+ get_debugger_deps = _get_debugger_deps,
+ get_extra_common_runfiles_for_binary = lambda ctx: ctx.runfiles(),
+ get_extra_providers = _get_extra_providers,
+ get_extra_write_build_data_env = lambda ctx: {},
+ get_imports = get_imports,
+ get_interpreter_path = _get_interpreter_path,
+ get_native_deps_dso_name = _get_native_deps_dso_name,
+ get_native_deps_user_link_flags = _get_native_deps_user_link_flags,
+ get_stamp_flag = _get_stamp_flag,
+ maybe_precompile = maybe_precompile,
+ should_build_native_deps_dso = lambda ctx: False,
+ should_create_init_files = _should_create_init_files,
+ should_include_build_data = lambda ctx: False,
+ # keep-sorted end
+ )
+
+def _get_coverage_deps(ctx, runtime_details):
+ _ = ctx, runtime_details # @unused
+ return []
+
+def _get_debugger_deps(ctx, runtime_details):
+ _ = ctx, runtime_details # @unused
+ return []
+
+def _get_extra_providers(ctx, main_py, runtime_details):
+ _ = ctx, main_py, runtime_details # @unused
+ return {}, []
+
+def _get_stamp_flag(ctx):
+ # NOTE: Undocumented API; private to builtins
+ return ctx.configuration.stamp_binaries
+
+def _should_create_init_files(ctx):
+ if ctx.attr.legacy_create_init == -1:
+ return not ctx.fragments.py.default_to_explicit_init_py
+ else:
+ return bool(ctx.attr.legacy_create_init)
+
+def _create_executable(
+ ctx,
+ *,
+ executable,
+ main_py,
+ imports,
+ is_test,
+ runtime_details,
+ cc_details,
+ native_deps_details,
+ runfiles_details):
+ _ = is_test, cc_details, native_deps_details # @unused
+
+ common_bootstrap_template_kwargs = dict(
+ main_py = main_py,
+ imports = imports,
+ runtime_details = runtime_details,
+ )
+
+ is_windows = target_platform_has_any_constraint(ctx, ctx.attr._windows_constraints)
+
+ if is_windows:
+ if not executable.extension == "exe":
+ fail("Should not happen: somehow we are generating a non-.exe file on windows")
+ base_executable_name = executable.basename[0:-4]
+ else:
+ base_executable_name = executable.basename
+
+ zip_bootstrap = ctx.actions.declare_file(base_executable_name + ".temp", sibling = executable)
+ zip_file = ctx.actions.declare_file(base_executable_name + ".zip", sibling = executable)
+
+ _expand_bootstrap_template(
+ ctx,
+ output = zip_bootstrap,
+ is_for_zip = True,
+ **common_bootstrap_template_kwargs
+ )
+ _create_zip_file(
+ ctx,
+ output = zip_file,
+ original_nonzip_executable = executable,
+ executable_for_zip_file = zip_bootstrap,
+ runfiles = runfiles_details.default_runfiles,
+ )
+
+ extra_files_to_build = []
+
+ # NOTE: --build_python_zip defaults to true on Windows
+ build_zip_enabled = ctx.fragments.py.build_python_zip
+
+ # When --build_python_zip is enabled, then the zip file becomes
+ # one of the default outputs.
+ if build_zip_enabled:
+ extra_files_to_build.append(zip_file)
+
+ # The logic here is a bit convoluted. Essentially, there are 3 types of
+ # executables produced:
+ # 1. (non-Windows) A bootstrap template based program.
+ # 2. (non-Windows) A self-executable zip file of a bootstrap template based program.
+ # 3. (Windows) A native Windows executable that finds and launches
+ # the actual underlying Bazel program (one of the above). Note that
+ # it implicitly assumes one of the above is located next to it, and
+ # that --build_python_zip defaults to true for Windows.
+
+ should_create_executable_zip = False
+ bootstrap_output = None
+ if not is_windows:
+ if build_zip_enabled:
+ should_create_executable_zip = True
+ else:
+ bootstrap_output = executable
+ else:
+ _create_windows_exe_launcher(
+ ctx,
+ output = executable,
+ use_zip_file = build_zip_enabled,
+ python_binary_path = runtime_details.executable_interpreter_path,
+ )
+ if not build_zip_enabled:
+ # On Windows, the main executable has an "exe" extension, so
+ # here we re-use the un-extensioned name for the bootstrap output.
+ bootstrap_output = ctx.actions.declare_file(base_executable_name)
+
+ # The launcher looks for the non-zip executable next to
+ # itself, so add it to the default outputs.
+ extra_files_to_build.append(bootstrap_output)
+
+ if should_create_executable_zip:
+ if bootstrap_output != None:
+ fail("Should not occur: bootstrap_output should not be used " +
+ "when creating an executable zip")
+ _create_executable_zip_file(ctx, output = executable, zip_file = zip_file)
+ elif bootstrap_output:
+ _expand_bootstrap_template(
+ ctx,
+ output = bootstrap_output,
+ is_for_zip = build_zip_enabled,
+ **common_bootstrap_template_kwargs
+ )
+ else:
+ # Otherwise, this should be the Windows case of launcher + zip.
+ # Double check this just to make sure.
+ if not is_windows or not build_zip_enabled:
+ fail(("Should not occur: The non-executable-zip and " +
+ "non-bootstrap-template case should have windows and zip " +
+ "both true, but got " +
+ "is_windows={is_windows} " +
+ "build_zip_enabled={build_zip_enabled}").format(
+ is_windows = is_windows,
+ build_zip_enabled = build_zip_enabled,
+ ))
+
+ return create_executable_result_struct(
+ extra_files_to_build = depset(extra_files_to_build),
+ output_groups = {"python_zip_file": depset([zip_file])},
+ )
+
+def _expand_bootstrap_template(
+ ctx,
+ *,
+ output,
+ main_py,
+ imports,
+ is_for_zip,
+ runtime_details):
+ runtime = runtime_details.effective_runtime
+ if (ctx.configuration.coverage_enabled and
+ runtime and
+ runtime.coverage_tool):
+ coverage_tool_runfiles_path = "{}/{}".format(
+ ctx.workspace_name,
+ runtime.coverage_tool.short_path,
+ )
+ else:
+ coverage_tool_runfiles_path = ""
+
+ if runtime:
+ shebang = runtime.stub_shebang
+ template = runtime.bootstrap_template
+ else:
+ shebang = DEFAULT_STUB_SHEBANG
+ template = ctx.file._bootstrap_template
+
+ ctx.actions.expand_template(
+ template = template,
+ output = output,
+ substitutions = {
+ "%coverage_tool%": coverage_tool_runfiles_path,
+ "%import_all%": "True" if ctx.fragments.bazel_py.python_import_all_repositories else "False",
+ "%imports%": ":".join(imports.to_list()),
+ "%is_zipfile%": "True" if is_for_zip else "False",
+ "%main%": "{}/{}".format(
+ ctx.workspace_name,
+ main_py.short_path,
+ ),
+ "%python_binary%": runtime_details.executable_interpreter_path,
+ "%shebang%": shebang,
+ "%target%": str(ctx.label),
+ "%workspace_name%": ctx.workspace_name,
+ },
+ is_executable = True,
+ )
+
+def _create_windows_exe_launcher(
+ ctx,
+ *,
+ output,
+ python_binary_path,
+ use_zip_file):
+ launch_info = ctx.actions.args()
+ launch_info.use_param_file("%s", use_always = True)
+ launch_info.set_param_file_format("multiline")
+ launch_info.add("binary_type=Python")
+ launch_info.add(ctx.workspace_name, format = "workspace_name=%s")
+ launch_info.add(
+ "1" if py_internal.runfiles_enabled(ctx) else "0",
+ format = "symlink_runfiles_enabled=%s",
+ )
+ launch_info.add(python_binary_path, format = "python_bin_path=%s")
+ launch_info.add("1" if use_zip_file else "0", format = "use_zip_file=%s")
+
+ ctx.actions.run(
+ executable = ctx.executable._windows_launcher_maker,
+ arguments = [ctx.executable._launcher.path, launch_info, output.path],
+ inputs = [ctx.executable._launcher],
+ outputs = [output],
+ mnemonic = "PyBuildLauncher",
+ progress_message = "Creating launcher for %{label}",
+ # Needed to inherit PATH when using non-MSVC compilers like MinGW
+ use_default_shell_env = True,
+ )
+
+def _create_zip_file(ctx, *, output, original_nonzip_executable, executable_for_zip_file, runfiles):
+ workspace_name = ctx.workspace_name
+ legacy_external_runfiles = _py_builtins.get_legacy_external_runfiles(ctx)
+
+ manifest = ctx.actions.args()
+ manifest.use_param_file("@%s", use_always = True)
+ manifest.set_param_file_format("multiline")
+
+ manifest.add("__main__.py={}".format(executable_for_zip_file.path))
+ manifest.add("__init__.py=")
+ manifest.add(
+ "{}=".format(
+ _get_zip_runfiles_path("__init__.py", workspace_name, legacy_external_runfiles),
+ ),
+ )
+ for path in runfiles.empty_filenames.to_list():
+ manifest.add("{}=".format(_get_zip_runfiles_path(path, workspace_name, legacy_external_runfiles)))
+
+ def map_zip_runfiles(file):
+ if file != original_nonzip_executable and file != output:
+ return "{}={}".format(
+ _get_zip_runfiles_path(file.short_path, workspace_name, legacy_external_runfiles),
+ file.path,
+ )
+ else:
+ return None
+
+ manifest.add_all(runfiles.files, map_each = map_zip_runfiles, allow_closure = True)
+
+ inputs = [executable_for_zip_file]
+ if _py_builtins.is_bzlmod_enabled(ctx):
+ zip_repo_mapping_manifest = ctx.actions.declare_file(
+ output.basename + ".repo_mapping",
+ sibling = output,
+ )
+ _py_builtins.create_repo_mapping_manifest(
+ ctx = ctx,
+ runfiles = runfiles,
+ output = zip_repo_mapping_manifest,
+ )
+ manifest.add("{}/_repo_mapping={}".format(
+ _ZIP_RUNFILES_DIRECTORY_NAME,
+ zip_repo_mapping_manifest.path,
+ ))
+ inputs.append(zip_repo_mapping_manifest)
+
+ for artifact in runfiles.files.to_list():
+ # Don't include the original executable because it isn't used by the
+ # zip file, so no need to build it for the action.
+ # Don't include the zipfile itself because it's an output.
+ if artifact != original_nonzip_executable and artifact != output:
+ inputs.append(artifact)
+
+ zip_cli_args = ctx.actions.args()
+ zip_cli_args.add("cC")
+ zip_cli_args.add(output)
+
+ ctx.actions.run(
+ executable = ctx.executable._zipper,
+ arguments = [zip_cli_args, manifest],
+ inputs = depset(inputs),
+ outputs = [output],
+ use_default_shell_env = True,
+ mnemonic = "PythonZipper",
+ progress_message = "Building Python zip: %{label}",
+ )
+
+def _get_zip_runfiles_path(path, workspace_name, legacy_external_runfiles):
+ if legacy_external_runfiles and path.startswith(_EXTERNAL_PATH_PREFIX):
+ zip_runfiles_path = paths.relativize(path, _EXTERNAL_PATH_PREFIX)
+ else:
+ # NOTE: External runfiles (artifacts in other repos) will have a leading
+ # path component of "../" so that they refer outside the main workspace
+ # directory and into the runfiles root. By normalizing, we simplify e.g.
+ # "workspace/../foo/bar" to simply "foo/bar".
+ zip_runfiles_path = paths.normalize("{}/{}".format(workspace_name, path))
+ return "{}/{}".format(_ZIP_RUNFILES_DIRECTORY_NAME, zip_runfiles_path)
+
+def _create_executable_zip_file(ctx, *, output, zip_file):
+ ctx.actions.run_shell(
+ command = "echo '{shebang}' | cat - {zip} > {output}".format(
+ shebang = "#!/usr/bin/env python3",
+ zip = zip_file.path,
+ output = output.path,
+ ),
+ inputs = [zip_file],
+ outputs = [output],
+ use_default_shell_env = True,
+ mnemonic = "BuildBinary",
+ progress_message = "Build Python zip executable: %{label}",
+ )
+
+def _get_cc_details_for_binary(ctx, extra_deps):
+ cc_info = collect_cc_info(ctx, extra_deps = extra_deps)
+ return create_cc_details_struct(
+ cc_info_for_propagating = cc_info,
+ cc_info_for_self_link = cc_info,
+ cc_info_with_extra_link_time_libraries = None,
+ extra_runfiles = ctx.runfiles(),
+ # Though the rules require the CcToolchain, it isn't actually used.
+ cc_toolchain = None,
+ )
+
+def _get_interpreter_path(ctx, *, runtime, flag_interpreter_path):
+ if runtime:
+ if runtime.interpreter_path:
+ interpreter_path = runtime.interpreter_path
+ else:
+ interpreter_path = "{}/{}".format(
+ ctx.workspace_name,
+ runtime.interpreter.short_path,
+ )
+
+ # NOTE: External runfiles (artifacts in other repos) will have a
+ # leading path component of "../" so that they refer outside the
+ # main workspace directory and into the runfiles root. By
+ # normalizing, we simplify e.g. "workspace/../foo/bar" to simply
+ # "foo/bar"
+ interpreter_path = paths.normalize(interpreter_path)
+
+ elif flag_interpreter_path:
+ interpreter_path = flag_interpreter_path
+ else:
+ fail("Unable to determine interpreter path")
+
+ return interpreter_path
+
+def _get_native_deps_dso_name(ctx):
+ _ = ctx # @unused
+ fail("Building native deps DSO not supported.")
+
+def _get_native_deps_user_link_flags(ctx):
+ _ = ctx # @unused
+ fail("Building native deps DSO not supported.")
diff --git a/python/private/common/py_internal.bzl b/python/private/common/py_internal.bzl
new file mode 100644
index 0000000..4296372
--- /dev/null
+++ b/python/private/common/py_internal.bzl
@@ -0,0 +1,26 @@
+# 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 RULE IMPLEMENTATION ONLY: Do not use outside of the rule implementations and their tests.
+
+Re-exports the restricted-use py_internal helper under its original name.
+
+These may change at any time and are closely coupled to the rule implementation.
+"""
+
+# The py_internal global is only available in Bazel 7+, so loading of it
+# must go through a repo rule with Bazel version detection logic.
+load("@rules_python_internal//:py_internal.bzl", "py_internal_impl")
+
+# NOTE: This is None prior to Bazel 7, as set by @rules_python_internal
+py_internal = py_internal_impl
diff --git a/python/private/common/py_library.bzl b/python/private/common/py_library.bzl
new file mode 100644
index 0000000..28ee7bf
--- /dev/null
+++ b/python/private/common/py_library.bzl
@@ -0,0 +1,102 @@
+# 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.
+"""Implementation of py_library rule."""
+
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load(
+ ":attributes.bzl",
+ "COMMON_ATTRS",
+ "PY_SRCS_ATTRS",
+ "SRCS_VERSION_ALL_VALUES",
+ "create_srcs_attr",
+ "create_srcs_version_attr",
+)
+load(
+ ":common.bzl",
+ "check_native_allowed",
+ "collect_imports",
+ "collect_runfiles",
+ "create_instrumented_files_info",
+ "create_output_group_info",
+ "create_py_info",
+ "filter_to_py_srcs",
+ "union_attrs",
+)
+load(":providers.bzl", "PyCcLinkParamsProvider")
+load(":py_internal.bzl", "py_internal")
+
+_py_builtins = py_internal
+
+LIBRARY_ATTRS = union_attrs(
+ COMMON_ATTRS,
+ PY_SRCS_ATTRS,
+ create_srcs_version_attr(values = SRCS_VERSION_ALL_VALUES),
+ create_srcs_attr(mandatory = False),
+)
+
+def py_library_impl(ctx, *, semantics):
+ """Abstract implementation of py_library rule.
+
+ Args:
+ ctx: The rule ctx
+ semantics: A `LibrarySemantics` struct; see `create_library_semantics_struct`
+
+ Returns:
+ A list of modern providers to propagate.
+ """
+ check_native_allowed(ctx)
+ direct_sources = filter_to_py_srcs(ctx.files.srcs)
+ output_sources = depset(semantics.maybe_precompile(ctx, direct_sources))
+ runfiles = collect_runfiles(ctx = ctx, files = output_sources)
+
+ cc_info = semantics.get_cc_info_for_library(ctx)
+ py_info, deps_transitive_sources, builtins_py_info = create_py_info(
+ ctx,
+ direct_sources = depset(direct_sources),
+ imports = collect_imports(ctx, semantics),
+ )
+
+ # TODO(b/253059598): Remove support for extra actions; https://github.com/bazelbuild/bazel/issues/16455
+ listeners_enabled = _py_builtins.are_action_listeners_enabled(ctx)
+ if listeners_enabled:
+ _py_builtins.add_py_extra_pseudo_action(
+ ctx = ctx,
+ dependency_transitive_python_sources = deps_transitive_sources,
+ )
+
+ return [
+ DefaultInfo(files = output_sources, runfiles = runfiles),
+ py_info,
+ builtins_py_info,
+ create_instrumented_files_info(ctx),
+ PyCcLinkParamsProvider(cc_info = cc_info),
+ create_output_group_info(py_info.transitive_sources, extra_groups = {}),
+ ]
+
+def create_py_library_rule(*, attrs = {}, **kwargs):
+ """Creates a py_library rule.
+
+ Args:
+ attrs: dict of rule attributes.
+ **kwargs: Additional kwargs to pass onto the rule() call.
+ Returns:
+ A rule object
+ """
+ return rule(
+ attrs = dicts.add(LIBRARY_ATTRS, attrs),
+ # TODO(b/253818097): fragments=py is only necessary so that
+ # RequiredConfigFragmentsTest passes
+ fragments = ["py"],
+ **kwargs
+ )
diff --git a/python/extensions/private/BUILD.bazel b/python/private/common/py_library_macro_bazel.bzl
index f367b71..b4f51ef 100644
--- a/python/extensions/private/BUILD.bazel
+++ b/python/private/common/py_library_macro_bazel.bzl
@@ -11,13 +11,9 @@
# 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.
+"""Implementation of macro-half of py_library rule."""
-package(default_visibility = ["//visibility:private"])
+load(":py_library_rule_bazel.bzl", py_library_rule = "py_library")
-licenses(["notice"])
-
-filegroup(
- name = "distribution",
- srcs = glob(["**"]),
- visibility = ["//python/extensions/private:__pkg__"],
-)
+def py_library(**kwargs):
+ py_library_rule(**kwargs)
diff --git a/python/private/common/py_library_rule_bazel.bzl b/python/private/common/py_library_rule_bazel.bzl
new file mode 100644
index 0000000..453abcb
--- /dev/null
+++ b/python/private/common/py_library_rule_bazel.bzl
@@ -0,0 +1,47 @@
+# 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.
+"""Implementation of py_library for Bazel."""
+
+load(":attributes_bazel.bzl", "IMPORTS_ATTRS")
+load(":common.bzl", "create_library_semantics_struct", "union_attrs")
+load(":common_bazel.bzl", "collect_cc_info", "get_imports", "maybe_precompile")
+load(
+ ":py_library.bzl",
+ "LIBRARY_ATTRS",
+ "create_py_library_rule",
+ bazel_py_library_impl = "py_library_impl",
+)
+
+_BAZEL_LIBRARY_ATTRS = union_attrs(
+ LIBRARY_ATTRS,
+ IMPORTS_ATTRS,
+)
+
+def create_library_semantics_bazel():
+ return create_library_semantics_struct(
+ get_imports = get_imports,
+ maybe_precompile = maybe_precompile,
+ get_cc_info_for_library = collect_cc_info,
+ )
+
+def _py_library_impl(ctx):
+ return bazel_py_library_impl(
+ ctx,
+ semantics = create_library_semantics_bazel(),
+ )
+
+py_library = create_py_library_rule(
+ implementation = _py_library_impl,
+ attrs = _BAZEL_LIBRARY_ATTRS,
+)
diff --git a/python/private/common/py_runtime_macro.bzl b/python/private/common/py_runtime_macro.bzl
new file mode 100644
index 0000000..7d04388
--- /dev/null
+++ b/python/private/common/py_runtime_macro.bzl
@@ -0,0 +1,22 @@
+# 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.
+"""Macro to wrap the py_runtime rule."""
+
+load(":py_runtime_rule.bzl", py_runtime_rule = "py_runtime")
+
+# NOTE: The function name is purposefully selected to match the underlying
+# rule name so that e.g. 'generator_function' shows as the same name so
+# that it is less confusing to users.
+def py_runtime(**kwargs):
+ py_runtime_rule(**kwargs)
diff --git a/python/private/common/py_runtime_rule.bzl b/python/private/common/py_runtime_rule.bzl
new file mode 100644
index 0000000..9d53543
--- /dev/null
+++ b/python/private/common/py_runtime_rule.bzl
@@ -0,0 +1,260 @@
+# 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.
+"""Implementation of py_runtime rule."""
+
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
+load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER")
+load(":attributes.bzl", "NATIVE_RULES_ALLOWLIST_ATTRS")
+load(":providers.bzl", "DEFAULT_BOOTSTRAP_TEMPLATE", "DEFAULT_STUB_SHEBANG", "PyRuntimeInfo")
+load(":py_internal.bzl", "py_internal")
+
+_py_builtins = py_internal
+
+def _py_runtime_impl(ctx):
+ interpreter_path = ctx.attr.interpreter_path or None # Convert empty string to None
+ interpreter = ctx.attr.interpreter
+ if (interpreter_path and interpreter) or (not interpreter_path and not interpreter):
+ fail("exactly one of the 'interpreter' or 'interpreter_path' attributes must be specified")
+
+ runtime_files = depset(transitive = [
+ t[DefaultInfo].files
+ for t in ctx.attr.files
+ ])
+
+ runfiles = ctx.runfiles()
+
+ hermetic = bool(interpreter)
+ if not hermetic:
+ if runtime_files:
+ fail("if 'interpreter_path' is given then 'files' must be empty")
+ if not paths.is_absolute(interpreter_path):
+ fail("interpreter_path must be an absolute path")
+ else:
+ interpreter_di = interpreter[DefaultInfo]
+
+ if interpreter_di.files_to_run and interpreter_di.files_to_run.executable:
+ interpreter = interpreter_di.files_to_run.executable
+ runfiles = runfiles.merge(interpreter_di.default_runfiles)
+
+ runtime_files = depset(transitive = [
+ interpreter_di.files,
+ interpreter_di.default_runfiles.files,
+ runtime_files,
+ ])
+ elif _is_singleton_depset(interpreter_di.files):
+ interpreter = interpreter_di.files.to_list()[0]
+ else:
+ fail("interpreter must be an executable target or must produce exactly one file.")
+
+ if ctx.attr.coverage_tool:
+ coverage_di = ctx.attr.coverage_tool[DefaultInfo]
+
+ if _is_singleton_depset(coverage_di.files):
+ coverage_tool = coverage_di.files.to_list()[0]
+ elif coverage_di.files_to_run and coverage_di.files_to_run.executable:
+ coverage_tool = coverage_di.files_to_run.executable
+ else:
+ fail("coverage_tool must be an executable target or must produce exactly one file.")
+
+ coverage_files = depset(transitive = [
+ coverage_di.files,
+ coverage_di.default_runfiles.files,
+ ])
+ else:
+ coverage_tool = None
+ coverage_files = None
+
+ python_version = ctx.attr.python_version
+
+ # TODO: Uncomment this after --incompatible_python_disable_py2 defaults to true
+ # if ctx.fragments.py.disable_py2 and python_version == "PY2":
+ # fail("Using Python 2 is not supported and disabled; see " +
+ # "https://github.com/bazelbuild/bazel/issues/15684")
+
+ py_runtime_info_kwargs = dict(
+ interpreter_path = interpreter_path or None,
+ interpreter = interpreter,
+ files = runtime_files if hermetic else None,
+ coverage_tool = coverage_tool,
+ coverage_files = coverage_files,
+ python_version = python_version,
+ stub_shebang = ctx.attr.stub_shebang,
+ bootstrap_template = ctx.file.bootstrap_template,
+ )
+ builtin_py_runtime_info_kwargs = dict(py_runtime_info_kwargs)
+ if not IS_BAZEL_7_OR_HIGHER:
+ builtin_py_runtime_info_kwargs.pop("bootstrap_template")
+ return [
+ PyRuntimeInfo(**py_runtime_info_kwargs),
+ # Return the builtin provider for better compatibility.
+ # 1. There is a legacy code path in py_binary that
+ # checks for the provider when toolchains aren't used
+ # 2. It makes it easier to transition from builtins to rules_python
+ BuiltinPyRuntimeInfo(**builtin_py_runtime_info_kwargs),
+ DefaultInfo(
+ files = runtime_files,
+ runfiles = runfiles,
+ ),
+ ]
+
+def _is_singleton_depset(files):
+ # Bazel 6 doesn't have this helper to optimize detecting singleton depsets.
+ if _py_builtins:
+ return _py_builtins.is_singleton_depset(files)
+ else:
+ return len(files.to_list()) == 1
+
+# Bind to the name "py_runtime" to preserve the kind/rule_class it shows up
+# as elsewhere.
+py_runtime = rule(
+ implementation = _py_runtime_impl,
+ doc = """
+Represents a Python runtime used to execute Python code.
+
+A `py_runtime` target can represent either a *platform runtime* or an *in-build
+runtime*. A platform runtime accesses a system-installed interpreter at a known
+path, whereas an in-build runtime points to an executable target that acts as
+the interpreter. In both cases, an "interpreter" means any executable binary or
+wrapper script that is capable of running a Python script passed on the command
+line, following the same conventions as the standard CPython interpreter.
+
+A platform runtime is by its nature non-hermetic. It imposes a requirement on
+the target platform to have an interpreter located at a specific path. An
+in-build runtime may or may not be hermetic, depending on whether it points to
+a checked-in interpreter or a wrapper script that accesses the system
+interpreter.
+
+# Example
+
+```
+load("@rules_python//python:py_runtime.bzl", "py_runtime")
+
+py_runtime(
+ name = "python-2.7.12",
+ files = glob(["python-2.7.12/**"]),
+ interpreter = "python-2.7.12/bin/python",
+)
+
+py_runtime(
+ name = "python-3.6.0",
+ interpreter_path = "/opt/pyenv/versions/3.6.0/bin/python",
+)
+```
+""",
+ fragments = ["py"],
+ attrs = dicts.add(NATIVE_RULES_ALLOWLIST_ATTRS, {
+ "bootstrap_template": attr.label(
+ allow_single_file = True,
+ default = DEFAULT_BOOTSTRAP_TEMPLATE,
+ doc = """
+The bootstrap script template file to use. Should have %python_binary%,
+%workspace_name%, %main%, and %imports%.
+
+This template, after expansion, becomes the executable file used to start the
+process, so it is responsible for initial bootstrapping actions such as finding
+the Python interpreter, runfiles, and constructing an environment to run the
+intended Python application.
+
+While this attribute is currently optional, it will become required when the
+Python rules are moved out of Bazel itself.
+
+The exact variable names expanded is an unstable API and is subject to change.
+The API will become more stable when the Python rules are moved out of Bazel
+itself.
+
+See @bazel_tools//tools/python:python_bootstrap_template.txt for more variables.
+""",
+ ),
+ "coverage_tool": attr.label(
+ allow_files = False,
+ doc = """
+This is a target to use for collecting code coverage information from `py_binary`
+and `py_test` targets.
+
+If set, the target must either produce a single file or be an executable target.
+The path to the single file, or the executable if the target is executable,
+determines the entry point for the python coverage tool. The target and its
+runfiles will be added to the runfiles when coverage is enabled.
+
+The entry point for the tool must be loadable by a Python interpreter (e.g. a
+`.py` or `.pyc` file). It must accept the command line arguments
+of coverage.py (https://coverage.readthedocs.io), at least including
+the `run` and `lcov` subcommands.
+""",
+ ),
+ "files": attr.label_list(
+ allow_files = True,
+ doc = """
+For an in-build runtime, this is the set of files comprising this runtime.
+These files will be added to the runfiles of Python binaries that use this
+runtime. For a platform runtime this attribute must not be set.
+""",
+ ),
+ "interpreter": attr.label(
+ # We set `allow_files = True` to allow specifying executable
+ # targets from rules that have more than one default output,
+ # e.g. sh_binary.
+ allow_files = True,
+ doc = """
+For an in-build runtime, this is the target to invoke as the interpreter. It
+can be either of:
+
+* A single file, which will be the interpreter binary. It's assumed such
+ interpreters are either self-contained single-file executables or any
+ supporting files are specified in `files`.
+* An executable target. The target's executable will be the interpreter binary.
+ Any other default outputs (`target.files`) and plain files runfiles
+ (`runfiles.files`) will be automatically included as if specified in the
+ `files` attribute.
+
+ NOTE: the runfiles of the target may not yet be properly respected/propagated
+ to consumers of the toolchain/interpreter, see
+ bazelbuild/rules_python/issues/1612
+
+For a platform runtime (i.e. `interpreter_path` being set) this attribute must
+not be set.
+""",
+ ),
+ "interpreter_path": attr.string(doc = """
+For a platform runtime, this is the absolute path of a Python interpreter on
+the target platform. For an in-build runtime this attribute must not be set.
+"""),
+ "python_version": attr.string(
+ default = "PY3",
+ values = ["PY2", "PY3"],
+ doc = """
+Whether this runtime is for Python major version 2 or 3. Valid values are `"PY2"`
+and `"PY3"`.
+
+The default value is controlled by the `--incompatible_py3_is_default` flag.
+However, in the future this attribute will be mandatory and have no default
+value.
+ """,
+ ),
+ "stub_shebang": attr.string(
+ default = DEFAULT_STUB_SHEBANG,
+ doc = """
+"Shebang" expression prepended to the bootstrapping Python stub script
+used when executing `py_binary` targets.
+
+See https://github.com/bazelbuild/bazel/issues/8685 for
+motivation.
+
+Does not apply to Windows.
+""",
+ ),
+ }),
+)
diff --git a/python/private/common/py_test_macro_bazel.bzl b/python/private/common/py_test_macro_bazel.bzl
new file mode 100644
index 0000000..24b78fe
--- /dev/null
+++ b/python/private/common/py_test_macro_bazel.bzl
@@ -0,0 +1,21 @@
+# 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.
+"""Implementation of macro-half of py_test rule."""
+
+load(":common_bazel.bzl", "convert_legacy_create_init_to_int")
+load(":py_test_rule_bazel.bzl", py_test_rule = "py_test")
+
+def py_test(**kwargs):
+ convert_legacy_create_init_to_int(kwargs)
+ py_test_rule(**kwargs)
diff --git a/python/private/common/py_test_rule_bazel.bzl b/python/private/common/py_test_rule_bazel.bzl
new file mode 100644
index 0000000..3479d03
--- /dev/null
+++ b/python/private/common/py_test_rule_bazel.bzl
@@ -0,0 +1,55 @@
+# 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.
+"""Rule implementation of py_test for Bazel."""
+
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load(":attributes.bzl", "AGNOSTIC_TEST_ATTRS")
+load(":common.bzl", "maybe_add_test_execution_info")
+load(
+ ":py_executable_bazel.bzl",
+ "create_executable_rule",
+ "py_executable_bazel_impl",
+)
+
+_BAZEL_PY_TEST_ATTRS = {
+ # This *might* be a magic attribute to help C++ coverage work. There's no
+ # docs about this; see TestActionBuilder.java
+ "_collect_cc_coverage": attr.label(
+ default = "@bazel_tools//tools/test:collect_cc_coverage",
+ executable = True,
+ cfg = "exec",
+ ),
+ # This *might* be a magic attribute to help C++ coverage work. There's no
+ # docs about this; see TestActionBuilder.java
+ "_lcov_merger": attr.label(
+ default = configuration_field(fragment = "coverage", name = "output_generator"),
+ cfg = "exec",
+ executable = True,
+ ),
+}
+
+def _py_test_impl(ctx):
+ providers = py_executable_bazel_impl(
+ ctx = ctx,
+ is_test = True,
+ inherited_environment = ctx.attr.env_inherit,
+ )
+ maybe_add_test_execution_info(providers.providers, ctx)
+ return providers
+
+py_test = create_executable_rule(
+ implementation = _py_test_impl,
+ attrs = dicts.add(AGNOSTIC_TEST_ATTRS, _BAZEL_PY_TEST_ATTRS),
+ test = True,
+)
diff --git a/python/private/common/semantics.bzl b/python/private/common/semantics.bzl
new file mode 100644
index 0000000..3811b17
--- /dev/null
+++ b/python/private/common/semantics.bzl
@@ -0,0 +1,31 @@
+# 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.
+"""Contains constants that vary between Bazel and Google-internal"""
+
+IMPORTS_ATTR_SUPPORTED = True
+
+SRCS_ATTR_ALLOW_FILES = [".py", ".py3"]
+
+DEPS_ATTR_ALLOW_RULES = None
+
+PY_RUNTIME_ATTR_NAME = "_py_interpreter"
+
+BUILD_DATA_SYMLINK_PATH = None
+
+IS_BAZEL = True
+
+NATIVE_RULES_MIGRATION_HELP_URL = "https://github.com/bazelbuild/bazel/issues/17773"
+NATIVE_RULES_MIGRATION_FIX_CMD = "add_python_loads"
+
+ALLOWED_MAIN_EXTENSIONS = [".py"]
diff --git a/python/private/coverage_deps.bzl b/python/private/coverage_deps.bzl
index 93938e9..7980779 100644
--- a/python/private/coverage_deps.bzl
+++ b/python/private/coverage_deps.bzl
@@ -19,8 +19,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load("//python/private:version_label.bzl", "version_label")
-# Update with './tools/update_coverage_deps.py <version>'
-#START: managed by update_coverage_deps.py script
+# START: maintained by 'bazel run //tools/private:update_coverage_deps'
_coverage_deps = {
"cp310": {
"aarch64-apple-darwin": (
@@ -95,12 +94,12 @@ _coverage_deps = {
),
},
}
-#END: managed by update_coverage_deps.py script
+# END: maintained by 'bazel run //tools/private:update_coverage_deps'
_coverage_patch = Label("//python/private:coverage.patch")
def coverage_dep(name, python_version, platform, visibility):
- """Register a singe coverage dependency based on the python version and platform.
+ """Register a single coverage dependency based on the python version and platform.
Args:
name: The name of the registered repository.
diff --git a/python/private/full_version.bzl b/python/private/full_version.bzl
new file mode 100644
index 0000000..68c9694
--- /dev/null
+++ b/python/private/full_version.bzl
@@ -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.
+
+"""A small helper to ensure that we are working with full versions."""
+
+load("//python:versions.bzl", "MINOR_MAPPING")
+
+def full_version(version):
+ """Return a full version.
+
+ Args:
+ version: the version in `X.Y` or `X.Y.Z` format.
+
+ Returns:
+ a full version given the version string. If the string is already a
+ major version then we return it as is.
+ """
+ if version in MINOR_MAPPING:
+ return MINOR_MAPPING[version]
+
+ parts = version.split(".")
+ if len(parts) == 3:
+ return version
+ elif len(parts) == 2:
+ fail(
+ "Unknown Python version '{}', available values are: {}".format(
+ version,
+ ",".join(MINOR_MAPPING.keys()),
+ ),
+ )
+ else:
+ fail("Unknown version format: {}".format(version))
diff --git a/python/private/internal_config_repo.bzl b/python/private/internal_config_repo.bzl
new file mode 100644
index 0000000..cfc7616
--- /dev/null
+++ b/python/private/internal_config_repo.bzl
@@ -0,0 +1,99 @@
+# 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.
+"""Repository to generate configuration settings info from the environment.
+
+This handles settings that can't be encoded as regular build configuration flags,
+such as globals available to Bazel versions, or propagating user environment
+settings for rules to later use.
+"""
+
+load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
+
+_ENABLE_PYSTAR_ENVVAR_NAME = "RULES_PYTHON_ENABLE_PYSTAR"
+_ENABLE_PYSTAR_DEFAULT = "0"
+
+_CONFIG_TEMPLATE = """\
+config = struct(
+ enable_pystar = {enable_pystar},
+)
+"""
+
+# The py_internal symbol is only accessible from within @rules_python, so we have to
+# load it from there and re-export it so that rules_python can later load it.
+_PY_INTERNAL_SHIM = """\
+load("@rules_python//tools/build_defs/python/private:py_internal_renamed.bzl", "py_internal_renamed")
+py_internal_impl = py_internal_renamed
+"""
+
+ROOT_BUILD_TEMPLATE = """\
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+package(
+ default_visibility = [
+ "{visibility}",
+ ]
+)
+
+bzl_library(
+ name = "rules_python_config_bzl",
+ srcs = ["rules_python_config.bzl"]
+)
+
+bzl_library(
+ name = "py_internal_bzl",
+ srcs = ["py_internal.bzl"],
+ deps = [{py_internal_dep}],
+)
+"""
+
+def _internal_config_repo_impl(rctx):
+ enable_pystar = _bool_from_environ(rctx, _ENABLE_PYSTAR_ENVVAR_NAME, _ENABLE_PYSTAR_DEFAULT)
+ rctx.file("rules_python_config.bzl", _CONFIG_TEMPLATE.format(
+ enable_pystar = enable_pystar,
+ ))
+
+ if enable_pystar or (
+ # Bazel 7+ (dev and later) has native.starlark_doc_extract, and thus the py_internal global
+ hasattr(native, "starlark_doc_extract") and
+ # The logic to allow the symbol doesn't work properly under bzlmod,
+ # even if the symbol is otherwise functional.
+ not BZLMOD_ENABLED
+ ):
+ shim_content = _PY_INTERNAL_SHIM
+ py_internal_dep = '"@rules_python//tools/build_defs/python/private:py_internal_renamed_bzl"'
+ else:
+ shim_content = "py_internal_impl = None\n"
+ py_internal_dep = ""
+
+ # Bazel 5 doesn't support repository visibility, so just use public
+ # as a stand-in
+ if native.bazel_version.startswith("5."):
+ visibility = "//visibility:public"
+ else:
+ visibility = "@rules_python//:__subpackages__"
+
+ rctx.file("BUILD", ROOT_BUILD_TEMPLATE.format(
+ py_internal_dep = py_internal_dep,
+ visibility = visibility,
+ ))
+ rctx.file("py_internal.bzl", shim_content)
+ return None
+
+internal_config_repo = repository_rule(
+ implementation = _internal_config_repo_impl,
+ environ = [_ENABLE_PYSTAR_ENVVAR_NAME],
+)
+
+def _bool_from_environ(rctx, key, default):
+ return bool(int(rctx.os.environ.get(key, default)))
diff --git a/python/private/labels.bzl b/python/private/labels.bzl
new file mode 100644
index 0000000..73df07b
--- /dev/null
+++ b/python/private/labels.bzl
@@ -0,0 +1,24 @@
+# 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.
+
+"""Constants used by parts of pip_repository for naming libraries and wheels."""
+
+WHEEL_FILE_PUBLIC_LABEL = "whl"
+WHEEL_FILE_IMPL_LABEL = "_whl"
+PY_LIBRARY_PUBLIC_LABEL = "pkg"
+PY_LIBRARY_IMPL_LABEL = "_pkg"
+DATA_LABEL = "data"
+DIST_INFO_LABEL = "dist_info"
+WHEEL_ENTRY_POINT_PREFIX = "rules_python_wheel_entry_point"
+NODEPS_LABEL = "no_deps"
diff --git a/python/private/parse_whl_name.bzl b/python/private/parse_whl_name.bzl
new file mode 100644
index 0000000..9c7866e
--- /dev/null
+++ b/python/private/parse_whl_name.bzl
@@ -0,0 +1,72 @@
+# 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.
+
+"""
+A starlark implementation of a Wheel filename parsing.
+"""
+
+def parse_whl_name(file):
+ """Parse whl file name into a struct of constituents.
+
+ Args:
+ file (str): The file name of a wheel
+
+ Returns:
+ A struct with the following attributes:
+ distribution: the distribution name
+ version: the version of the distribution
+ build_tag: the build tag for the wheel. None if there was no
+ build_tag in the given string.
+ python_tag: the python tag for the wheel
+ abi_tag: the ABI tag for the wheel
+ platform_tag: the platform tag
+ """
+ if not file.endswith(".whl"):
+ fail("not a valid wheel: {}".format(file))
+
+ file = file[:-len(".whl")]
+
+ # Parse the following
+ # {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
+ #
+ # For more info, see the following standards:
+ # https://packaging.python.org/en/latest/specifications/binary-distribution-format/#binary-distribution-format
+ # https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/
+ head, _, platform_tag = file.rpartition("-")
+ if not platform_tag:
+ fail("cannot extract platform tag from the whl filename: {}".format(file))
+ head, _, abi_tag = head.rpartition("-")
+ if not abi_tag:
+ fail("cannot extract abi tag from the whl filename: {}".format(file))
+ head, _, python_tag = head.rpartition("-")
+ if not python_tag:
+ fail("cannot extract python tag from the whl filename: {}".format(file))
+ head, _, version = head.rpartition("-")
+ if not version:
+ fail("cannot extract version from the whl filename: {}".format(file))
+ distribution, _, maybe_version = head.partition("-")
+
+ if maybe_version:
+ version, build_tag = maybe_version, version
+ else:
+ build_tag = None
+
+ return struct(
+ distribution = distribution,
+ version = version,
+ build_tag = build_tag,
+ python_tag = python_tag,
+ abi_tag = abi_tag,
+ platform_tag = platform_tag,
+ )
diff --git a/python/private/patch_whl.bzl b/python/private/patch_whl.bzl
new file mode 100644
index 0000000..9e3119f
--- /dev/null
+++ b/python/private/patch_whl.bzl
@@ -0,0 +1,119 @@
+# 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.
+
+"""A small utility to patch a file in the repository context and repackage it using a Python interpreter
+
+Note, because we are patching a wheel file and we need a new RECORD file, this
+function will print a diff of the RECORD and will ask the user to include a
+RECORD patch in their patches that they maintain. This is to ensure that we can
+satisfy the following usecases:
+* Patch an invalid RECORD file.
+* Patch files within a wheel.
+
+If we were silently regenerating the RECORD file, we may be vulnerable to supply chain
+attacks (it is a very small chance) and keeping the RECORD patches next to the
+other patches ensures that the users have overview on exactly what has changed
+within the wheel.
+"""
+
+load("//python/private:parse_whl_name.bzl", "parse_whl_name")
+
+_rules_python_root = Label("//:BUILD.bazel")
+
+def patch_whl(rctx, *, python_interpreter, whl_path, patches, **kwargs):
+ """Patch a whl file and repack it to ensure that the RECORD metadata stays correct.
+
+ Args:
+ rctx: repository_ctx
+ python_interpreter: the python interpreter to use.
+ whl_path: The whl file name to be patched.
+ patches: a label-keyed-int dict that has the patch files as keys and
+ the patch_strip as the value.
+ **kwargs: extras passed to rctx.execute.
+
+ Returns:
+ value of the repackaging action.
+ """
+
+ # extract files into the current directory for patching as rctx.patch
+ # does not support patching in another directory.
+ whl_input = rctx.path(whl_path)
+
+ # symlink to a zip file to use bazel's extract so that we can use bazel's
+ # repository_ctx patch implementation. The whl file may be in a different
+ # external repository.
+ whl_file_zip = whl_input.basename + ".zip"
+ rctx.symlink(whl_input, whl_file_zip)
+ rctx.extract(whl_file_zip)
+ if not rctx.delete(whl_file_zip):
+ fail("Failed to remove the symlink after extracting")
+
+ for patch_file, patch_strip in patches.items():
+ rctx.patch(patch_file, strip = patch_strip)
+
+ # Generate an output filename, which we will be returning
+ parsed_whl = parse_whl_name(whl_input.basename)
+ whl_patched = "{}.whl".format("-".join([
+ parsed_whl.distribution,
+ parsed_whl.version,
+ (parsed_whl.build_tag or "") + "patched",
+ parsed_whl.python_tag,
+ parsed_whl.abi_tag,
+ parsed_whl.platform_tag,
+ ]))
+
+ record_patch = rctx.path("RECORD.patch")
+
+ result = rctx.execute(
+ [
+ python_interpreter,
+ "-m",
+ "python.private.repack_whl",
+ "--record-patch",
+ record_patch,
+ whl_input,
+ whl_patched,
+ ],
+ environment = {
+ "PYTHONPATH": str(rctx.path(_rules_python_root).dirname),
+ },
+ **kwargs
+ )
+
+ if result.return_code:
+ fail(
+ "repackaging .whl {whl} failed: with exit code '{return_code}':\n{stdout}\n\nstderr:\n{stderr}".format(
+ whl = whl_input.basename,
+ stdout = result.stdout,
+ stderr = result.stderr,
+ return_code = result.return_code,
+ ),
+ )
+
+ if record_patch.exists:
+ record_patch_contents = rctx.read(record_patch)
+ warning_msg = """WARNING: the resultant RECORD file of the patch wheel is different
+
+ If you are patching on Windows, you may see this warning because of
+ a known issue (bazelbuild/rules_python#1639) with file endings.
+
+ If you would like to silence the warning, you can apply the patch that is stored in
+ {record_patch}. The contents of the file are below:
+{record_patch_contents}""".format(
+ record_patch = record_patch,
+ record_patch_contents = record_patch_contents,
+ )
+ print(warning_msg) # buildifier: disable=print
+
+ return rctx.path(whl_patched)
diff --git a/python/private/proto/py_proto_library.bzl b/python/private/proto/py_proto_library.bzl
index 9377c85..91faa2d 100644
--- a/python/private/proto/py_proto_library.bzl
+++ b/python/private/proto/py_proto_library.bzl
@@ -66,6 +66,7 @@ def _py_proto_aspect_impl(target, ctx):
generated_sources = []
proto_info = target[ProtoInfo]
+ proto_root = proto_info.proto_source_root
if proto_info.direct_sources:
# Generate py files
generated_sources = proto_common.declare_generated_files(
@@ -76,14 +77,11 @@ def _py_proto_aspect_impl(target, ctx):
)
# Handles multiple repository and virtual import cases
- proto_root = proto_info.proto_source_root
if proto_root.startswith(ctx.bin_dir.path):
- plugin_output = proto_root
- else:
- plugin_output = ctx.bin_dir.path + "/" + proto_root
+ proto_root = proto_root[len(ctx.bin_dir.path) + 1:]
- if plugin_output == ".":
- plugin_output = ctx.bin_dir.path
+ plugin_output = ctx.bin_dir.path + "/" + proto_root
+ proto_root = ctx.workspace_name + "/" + proto_root
proto_common.compile(
actions = ctx.actions,
@@ -109,7 +107,14 @@ def _py_proto_aspect_impl(target, ctx):
return [
_PyProtoInfo(
imports = depset(
- transitive = [dep[PyInfo].imports for dep in api_deps],
+ # Adding to PYTHONPATH so the generated modules can be
+ # imported. This is necessary when there is
+ # strip_import_prefix, the Python modules are generated under
+ # _virtual_imports. But it's undesirable otherwise, because it
+ # will put the repo root at the top of the PYTHONPATH, ahead of
+ # directories added through `imports` attributes.
+ [proto_root] if "_virtual_imports" in proto_root else [],
+ transitive = [dep[PyInfo].imports for dep in api_deps] + [dep.imports for dep in deps],
),
runfiles_from_proto_deps = runfiles_from_proto_deps,
transitive_sources = transitive_sources,
diff --git a/python/private/py_cc_toolchain_info.bzl b/python/private/py_cc_toolchain_info.bzl
index e7afc10..a2e62a8 100644
--- a/python/private/py_cc_toolchain_info.bzl
+++ b/python/private/py_cc_toolchain_info.bzl
@@ -33,7 +33,7 @@ PyCcToolchainInfo = provider(
When consuming this map, it's suggested to use `providers_map.values()` to
return all providers; or copy the map and filter out or replace keys as
- appropriate. Note that any keys begining with `_` (underscore) are
+ appropriate. Note that any keys beginning with `_` (underscore) are
considered private and should be forward along as-is (this better allows
e.g. `:current_py_cc_headers` to act as the underlying headers target it
represents).
diff --git a/python/private/py_console_script_binary.bzl b/python/private/py_console_script_binary.bzl
new file mode 100644
index 0000000..deeded2
--- /dev/null
+++ b/python/private/py_console_script_binary.bzl
@@ -0,0 +1,87 @@
+# 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.
+
+"""
+Implementation for the macro to generate a console_script py_binary from an 'entry_points.txt' config.
+"""
+
+load("//python:py_binary.bzl", "py_binary")
+load(":py_console_script_gen.bzl", "py_console_script_gen")
+
+def _dist_info(pkg):
+ """Return the first candidate for the dist_info target label.
+
+ We cannot do `Label(pkg)` here because the string will be evaluated within
+ the context of the rules_python repo_mapping and it will fail because
+ rules_python does not know anything about the hub repos that the user has
+ available.
+
+ NOTE: Works with `incompatible_generate_aliases` and without by assuming the
+ following formats:
+ * @pypi_pylint//:pkg
+ * @pypi//pylint
+ * @pypi//pylint:pkg
+ * Label("@pypi//pylint:pkg")
+ """
+
+ # str() is called to convert Label objects
+ return str(pkg).replace(":pkg", "") + ":dist_info"
+
+def py_console_script_binary(
+ *,
+ name,
+ pkg,
+ entry_points_txt = None,
+ script = None,
+ binary_rule = py_binary,
+ **kwargs):
+ """Generate a py_binary for a console_script entry_point.
+
+ Args:
+ name: [`target-name`] The name of the resulting target.
+ pkg: {any}`simple label` the package for which to generate the script.
+ entry_points_txt: optional [`label`], the entry_points.txt file to parse
+ for available console_script values. It may be a single file, or a
+ group of files, but must contain a file named `entry_points.txt`.
+ If not specified, defaults to the `dist_info` target in the same
+ package as the `pkg` Label.
+ script: [`str`], The console script name that the py_binary is going to be
+ generated for. Defaults to the normalized name attribute.
+ binary_rule: {any}`rule callable`, The rule/macro to use to instantiate
+ the target. It's expected to behave like {any}`py_binary`.
+ Defaults to {any}`py_binary`.
+ **kwargs: Extra parameters forwarded to `binary_rule`.
+ """
+ main = "rules_python_entry_point_{}.py".format(name)
+
+ if kwargs.pop("srcs", None):
+ fail("passing 'srcs' attribute to py_console_script_binary is unsupported")
+
+ py_console_script_gen(
+ name = "_{}_gen".format(name),
+ # NOTE @aignas 2023-08-05: Works with `incompatible_generate_aliases` and without.
+ entry_points_txt = entry_points_txt or _dist_info(pkg),
+ out = main,
+ console_script = script,
+ console_script_guess = name,
+ visibility = ["//visibility:private"],
+ )
+
+ binary_rule(
+ name = name,
+ srcs = [main],
+ main = main,
+ deps = [pkg] + kwargs.pop("deps", []),
+ **kwargs
+ )
diff --git a/python/private/py_console_script_gen.bzl b/python/private/py_console_script_gen.bzl
new file mode 100644
index 0000000..7dd4dd2
--- /dev/null
+++ b/python/private/py_console_script_gen.bzl
@@ -0,0 +1,93 @@
+# 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.
+
+"""
+A private rule to generate an entry_point python file to be used in a py_binary.
+
+Right now it only supports console_scripts via the entry_points.txt file in the dist-info.
+
+NOTE @aignas 2023-08-07: This cannot be in pure starlark, because we need to
+read a file and then create a `.py` file based on the contents of that file,
+which cannot be done in pure starlark according to
+https://github.com/bazelbuild/bazel/issues/14744
+"""
+
+_ENTRY_POINTS_TXT = "entry_points.txt"
+
+def _get_entry_points_txt(entry_points_txt):
+ """Get the entry_points.txt file
+
+ TODO: use map_each to avoid flattening of the directories outside the execution phase.
+ """
+ for file in entry_points_txt.files.to_list():
+ if file.basename == _ENTRY_POINTS_TXT:
+ return file
+
+ fail("{} does not contain {}".format(entry_points_txt, _ENTRY_POINTS_TXT))
+
+def _py_console_script_gen_impl(ctx):
+ entry_points_txt = _get_entry_points_txt(ctx.attr.entry_points_txt)
+
+ args = ctx.actions.args()
+ args.add("--console-script", ctx.attr.console_script)
+ args.add("--console-script-guess", ctx.attr.console_script_guess)
+ args.add(entry_points_txt)
+ args.add(ctx.outputs.out)
+
+ ctx.actions.run(
+ inputs = [
+ entry_points_txt,
+ ],
+ outputs = [ctx.outputs.out],
+ arguments = [args],
+ mnemonic = "PyConsoleScriptBinaryGen",
+ progress_message = "Generating py_console_script_binary main: %{label}",
+ executable = ctx.executable._tool,
+ )
+
+ return [DefaultInfo(
+ files = depset([ctx.outputs.out]),
+ )]
+
+py_console_script_gen = rule(
+ _py_console_script_gen_impl,
+ attrs = {
+ "console_script": attr.string(
+ doc = "The name of the console_script to create the .py file for. Optional if there is only a single entry-point available.",
+ default = "",
+ mandatory = False,
+ ),
+ "console_script_guess": attr.string(
+ doc = "The string used for guessing the console_script if it is not provided.",
+ default = "",
+ mandatory = False,
+ ),
+ "entry_points_txt": attr.label(
+ doc = "The filegroup to search for entry_points.txt.",
+ mandatory = True,
+ ),
+ "out": attr.output(
+ doc = "Output file location.",
+ mandatory = True,
+ ),
+ "_tool": attr.label(
+ default = ":py_console_script_gen_py",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+ doc = """\
+Builds an entry_point script from an entry_points.txt file.
+""",
+)
diff --git a/python/private/py_console_script_gen.py b/python/private/py_console_script_gen.py
new file mode 100644
index 0000000..64ebea6
--- /dev/null
+++ b/python/private/py_console_script_gen.py
@@ -0,0 +1,180 @@
+# 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.
+
+"""
+console_script generator from entry_points.txt contents.
+
+For Python versions earlier than 3.11 and for earlier bazel versions than 7.0 we need to workaround the issue of
+sys.path[0] breaking out of the runfiles tree see the following for more context:
+* https://github.com/bazelbuild/rules_python/issues/382
+* https://github.com/bazelbuild/bazel/pull/15701
+
+In affected bazel and Python versions we see in programs such as `flake8`, `pylint` or `pytest` errors because the
+first `sys.path` element is outside the `runfiles` directory and if the `name` of the `py_binary` is the same as
+the program name, then the script (e.g. `flake8`) will start failing whilst trying to import its own internals from
+the bazel entrypoint script.
+
+The mitigation strategy is to remove the first entry in the `sys.path` if it does not have `.runfiles` and it seems
+to fix the behaviour of console_scripts under `bazel run`.
+
+This would not happen if we created a console_script binary in the root of an external repository, e.g.
+`@pypi_pylint//` because the path for the external repository is already in the runfiles directory.
+"""
+
+from __future__ import annotations
+
+import argparse
+import configparser
+import pathlib
+import re
+import sys
+import textwrap
+
+_ENTRY_POINTS_TXT = "entry_points.txt"
+
+_TEMPLATE = """\
+import sys
+
+# See @rules_python//python/private:py_console_script_gen.py for explanation
+if getattr(sys.flags, "safe_path", False):
+ # We are running on Python 3.11 and we don't need this workaround
+ pass
+elif ".runfiles" not in sys.path[0]:
+ sys.path = sys.path[1:]
+
+try:
+ from {module} import {attr}
+except ImportError:
+ entries = "\\n".join(sys.path)
+ print("Printing sys.path entries for easier debugging:", file=sys.stderr)
+ print(f"sys.path is:\\n{{entries}}", file=sys.stderr)
+ raise
+
+if __name__ == "__main__":
+ sys.exit({entry_point}())
+"""
+
+
+class EntryPointsParser(configparser.ConfigParser):
+ """A class handling entry_points.txt
+
+ See https://packaging.python.org/en/latest/specifications/entry-points/
+ """
+
+ optionxform = staticmethod(str)
+
+
+def _guess_entry_point(guess: str, console_scripts: dict[string, string]) -> str | None:
+ for key, candidate in console_scripts.items():
+ if guess == key:
+ return candidate
+
+
+def run(
+ *,
+ entry_points: pathlib.Path,
+ out: pathlib.Path,
+ console_script: str,
+ console_script_guess: str,
+):
+ """Run the generator
+
+ Args:
+ entry_points: The entry_points.txt file to be parsed.
+ out: The output file.
+ console_script: The console_script entry in the entry_points.txt file.
+ """
+ config = EntryPointsParser()
+ config.read(entry_points)
+
+ try:
+ console_scripts = dict(config["console_scripts"])
+ except KeyError:
+ raise RuntimeError(
+ f"The package does not provide any console_scripts in its {_ENTRY_POINTS_TXT}"
+ )
+
+ if console_script:
+ try:
+ entry_point = console_scripts[console_script]
+ except KeyError:
+ available = ", ".join(sorted(console_scripts.keys()))
+ raise RuntimeError(
+ f"The console_script '{console_script}' was not found, only the following are available: {available}"
+ ) from None
+ else:
+ # Get rid of the extension and the common prefix
+ entry_point = _guess_entry_point(
+ guess=console_script_guess,
+ console_scripts=console_scripts,
+ )
+
+ if not entry_point:
+ available = ", ".join(sorted(console_scripts.keys()))
+ raise RuntimeError(
+ f"Tried to guess that you wanted '{console_script_guess}', but could not find it. "
+ f"Please select one of the following console scripts: {available}"
+ ) from None
+
+ module, _, entry_point = entry_point.rpartition(":")
+ attr, _, _ = entry_point.partition(".")
+ # TODO: handle 'extras' in entry_point generation
+ # See https://github.com/bazelbuild/rules_python/issues/1383
+ # See https://packaging.python.org/en/latest/specifications/entry-points/
+
+ with open(out, "w") as f:
+ f.write(
+ _TEMPLATE.format(
+ module=module,
+ attr=attr,
+ entry_point=entry_point,
+ ),
+ )
+
+
+def main():
+ parser = argparse.ArgumentParser(description="console_script generator")
+ parser.add_argument(
+ "--console-script",
+ help="The console_script to generate the entry_point template for.",
+ )
+ parser.add_argument(
+ "--console-script-guess",
+ required=True,
+ help="The string used for guessing the console_script if it is not provided.",
+ )
+ parser.add_argument(
+ "entry_points",
+ metavar="ENTRY_POINTS_TXT",
+ type=pathlib.Path,
+ help="The entry_points.txt within the dist-info of a PyPI wheel",
+ )
+ parser.add_argument(
+ "out",
+ type=pathlib.Path,
+ metavar="OUT",
+ help="The output file.",
+ )
+ args = parser.parse_args()
+
+ run(
+ entry_points=args.entry_points,
+ out=args.out,
+ console_script=args.console_script,
+ console_script_guess=args.console_script_guess,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/private/py_runtime_pair_macro.bzl b/python/private/py_runtime_pair_macro.bzl
new file mode 100644
index 0000000..3cc3599
--- /dev/null
+++ b/python/private/py_runtime_pair_macro.bzl
@@ -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.
+
+"""Implementation of py_runtime_pair macro portion."""
+
+load(":py_runtime_pair_rule.bzl", _py_runtime_pair = "py_runtime_pair")
+
+# A fronting macro is used because macros have user-observable behavior;
+# using one from the onset avoids introducing those changes in the future.
+def py_runtime_pair(**kwargs):
+ """Creates a py_runtime_pair target.
+
+ Args:
+ **kwargs: Keyword args to pass onto underlying rule.
+ """
+ _py_runtime_pair(**kwargs)
diff --git a/python/private/py_runtime_pair_rule.bzl b/python/private/py_runtime_pair_rule.bzl
new file mode 100644
index 0000000..d17b008
--- /dev/null
+++ b/python/private/py_runtime_pair_rule.bzl
@@ -0,0 +1,151 @@
+# Copyright 2019 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.
+
+"""Implementation of py_runtime_pair."""
+
+load("//python:py_runtime_info.bzl", "PyRuntimeInfo")
+load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
+load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER")
+
+def _py_runtime_pair_impl(ctx):
+ if ctx.attr.py2_runtime != None:
+ py2_runtime = _get_py_runtime_info(ctx.attr.py2_runtime)
+ if py2_runtime.python_version != "PY2":
+ fail("The Python runtime in the 'py2_runtime' attribute did not have " +
+ "version 'PY2'")
+ else:
+ py2_runtime = None
+
+ if ctx.attr.py3_runtime != None:
+ py3_runtime = _get_py_runtime_info(ctx.attr.py3_runtime)
+ if py3_runtime.python_version != "PY3":
+ fail("The Python runtime in the 'py3_runtime' attribute did not have " +
+ "version 'PY3'")
+ else:
+ py3_runtime = None
+
+ # TODO: Uncomment this after --incompatible_python_disable_py2 defaults to true
+ # if _is_py2_disabled(ctx) and py2_runtime != None:
+ # fail("Using Python 2 is not supported and disabled; see " +
+ # "https://github.com/bazelbuild/bazel/issues/15684")
+
+ return [platform_common.ToolchainInfo(
+ py2_runtime = py2_runtime,
+ py3_runtime = py3_runtime,
+ )]
+
+def _get_py_runtime_info(target):
+ # Prior to Bazel 7, the builtin PyRuntimeInfo object must be used because
+ # py_binary (implemented in Java) performs a type check on the provider
+ # value to verify it is an instance of the Java-implemented PyRuntimeInfo
+ # class.
+ if IS_BAZEL_7_OR_HIGHER and PyRuntimeInfo in target:
+ return target[PyRuntimeInfo]
+ else:
+ return target[BuiltinPyRuntimeInfo]
+
+# buildifier: disable=unused-variable
+def _is_py2_disabled(ctx):
+ # Because this file isn't bundled with Bazel, so we have to conditionally
+ # check for this flag.
+ # TODO: Remove this once all supported Balze versions have this flag.
+ if not hasattr(ctx.fragments.py, "disable_py"):
+ return False
+ return ctx.fragments.py.disable_py2
+
+py_runtime_pair = rule(
+ implementation = _py_runtime_pair_impl,
+ attrs = {
+ # The two runtimes are used by the py_binary at runtime, and so need to
+ # be built for the target platform.
+ "py2_runtime": attr.label(
+ providers = [[PyRuntimeInfo], [BuiltinPyRuntimeInfo]],
+ cfg = "target",
+ doc = """\
+The runtime to use for Python 2 targets. Must have `python_version` set to
+`PY2`.
+""",
+ ),
+ "py3_runtime": attr.label(
+ providers = [[PyRuntimeInfo], [BuiltinPyRuntimeInfo]],
+ cfg = "target",
+ doc = """\
+The runtime to use for Python 3 targets. Must have `python_version` set to
+`PY3`.
+""",
+ ),
+ },
+ fragments = ["py"],
+ doc = """\
+A toolchain rule for Python.
+
+This wraps up to two Python runtimes, one for Python 2 and one for Python 3.
+The rule consuming this toolchain will choose which runtime is appropriate.
+Either runtime may be omitted, in which case the resulting toolchain will be
+unusable for building Python code using that version.
+
+Usually the wrapped runtimes are declared using the `py_runtime` rule, but any
+rule returning a `PyRuntimeInfo` provider may be used.
+
+This rule returns a `platform_common.ToolchainInfo` provider with the following
+schema:
+
+```python
+platform_common.ToolchainInfo(
+ py2_runtime = <PyRuntimeInfo or None>,
+ py3_runtime = <PyRuntimeInfo or None>,
+)
+```
+
+Example usage:
+
+```python
+# In your BUILD file...
+
+load("@rules_python//python:py_runtime.bzl", "py_runtime")
+load("@rules_python//python:py_runtime_pair.bzl", "py_runtime_pair")
+
+py_runtime(
+ name = "my_py2_runtime",
+ interpreter_path = "/system/python2",
+ python_version = "PY2",
+)
+
+py_runtime(
+ name = "my_py3_runtime",
+ interpreter_path = "/system/python3",
+ python_version = "PY3",
+)
+
+py_runtime_pair(
+ name = "my_py_runtime_pair",
+ py2_runtime = ":my_py2_runtime",
+ py3_runtime = ":my_py3_runtime",
+)
+
+toolchain(
+ name = "my_toolchain",
+ target_compatible_with = <...>,
+ toolchain = ":my_py_runtime_pair",
+ toolchain_type = "@rules_python//python:toolchain_type",
+)
+```
+
+```python
+# In your WORKSPACE...
+
+register_toolchains("//my_pkg:my_toolchain")
+```
+""",
+)
diff --git a/python/private/py_wheel.bzl b/python/private/py_wheel.bzl
index d8bceab..f451389 100644
--- a/python/private/py_wheel.bzl
+++ b/python/private/py_wheel.bzl
@@ -16,6 +16,7 @@
load("//python/private:stamp.bzl", "is_stamping_enabled")
load(":py_package.bzl", "py_package_lib")
+load(":py_wheel_normalize_pep440.bzl", "normalize_pep440")
PyWheelInfo = provider(
doc = "Information about a wheel produced by `py_wheel`",
@@ -105,10 +106,10 @@ For example:
Note that Bazel's output filename cannot include the stamp information, as outputs must be known
during the analysis phase and the stamp data is available only during the action execution.
-The [`py_wheel`](/docs/packaging.md#py_wheel) macro produces a `.dist`-suffix target which creates a
+The [`py_wheel`](#py_wheel) macro produces a `.dist`-suffix target which creates a
`dist/` folder containing the wheel with the stamped name, suitable for publishing.
-See [`py_wheel_dist`](/docs/packaging.md#py_wheel_dist) for more info.
+See [`py_wheel_dist`](#py_wheel_dist) for more info.
""",
),
"_stamp_flag": attr.label(
@@ -117,6 +118,29 @@ See [`py_wheel_dist`](/docs/packaging.md#py_wheel_dist) for more info.
),
}
+_feature_flags = {
+ "incompatible_normalize_name": attr.bool(
+ default = True,
+ doc = """\
+Normalize the package distribution name according to latest
+Python packaging standards.
+
+See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
+and https://packaging.python.org/en/latest/specifications/name-normalization/.
+
+Apart from the valid names according to the above, we also accept
+'{' and '}', which may be used as placeholders for stamping.
+""",
+ ),
+ "incompatible_normalize_version": attr.bool(
+ default = True,
+ doc = "Normalize the package version according to PEP440 standard. " +
+ "With this option set to True, if the user wants to pass any " +
+ "stamp variables, they have to be enclosed in '{}', e.g. " +
+ "'{BUILD_TIMESTAMP}'.",
+ ),
+}
+
_requirement_attrs = {
"extra_requires": attr.string_list_dict(
doc = "List of optional requirements for this package",
@@ -203,6 +227,42 @@ _DESCRIPTION_FILE_EXTENSION_TO_TYPE = {
}
_DEFAULT_DESCRIPTION_FILE_TYPE = "text/plain"
+def _escape_filename_distribution_name(name):
+ """Escape the distribution name component of a filename.
+
+ See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
+ and https://packaging.python.org/en/latest/specifications/name-normalization/.
+
+ Apart from the valid names according to the above, we also accept
+ '{' and '}', which may be used as placeholders for stamping.
+ """
+ escaped = ""
+ for character in name.elems():
+ if character.isalnum() or character in ["{", "}"]:
+ escaped += character.lower()
+ elif character in ["-", "_", "."]:
+ if escaped == "":
+ fail(
+ "A valid name must start with a letter or number.",
+ "Name '%s' does not." % name,
+ )
+ elif escaped.endswith("_"):
+ pass
+ else:
+ escaped += "_"
+ else:
+ fail(
+ "A valid name consists only of ASCII letters ",
+ "and numbers, period, underscore and hyphen.",
+ "Name '%s' has bad character '%s'." % (name, character),
+ )
+ if escaped.endswith("_"):
+ fail(
+ "A valid name must end with a letter or number.",
+ "Name '%s' does not." % name,
+ )
+ return escaped
+
def _escape_filename_segment(segment):
"""Escape a segment of the wheel filename.
@@ -237,13 +297,25 @@ def _py_wheel_impl(ctx):
python_tag = _replace_make_variables(ctx.attr.python_tag, ctx)
version = _replace_make_variables(ctx.attr.version, ctx)
- outfile = ctx.actions.declare_file("-".join([
- _escape_filename_segment(ctx.attr.distribution),
- _escape_filename_segment(version),
+ filename_segments = []
+
+ if ctx.attr.incompatible_normalize_name:
+ filename_segments.append(_escape_filename_distribution_name(ctx.attr.distribution))
+ else:
+ filename_segments.append(_escape_filename_segment(ctx.attr.distribution))
+
+ if ctx.attr.incompatible_normalize_version:
+ filename_segments.append(normalize_pep440(version))
+ else:
+ filename_segments.append(_escape_filename_segment(version))
+
+ filename_segments.extend([
_escape_filename_segment(python_tag),
_escape_filename_segment(abi),
_escape_filename_segment(ctx.attr.platform),
- ]) + ".whl")
+ ])
+
+ outfile = ctx.actions.declare_file("-".join(filename_segments) + ".whl")
name_file = ctx.actions.declare_file(ctx.label.name + ".name")
@@ -272,6 +344,10 @@ def _py_wheel_impl(ctx):
args.add("--out", outfile)
args.add("--name_file", name_file)
args.add_all(ctx.attr.strip_path_prefixes, format_each = "--strip_path_prefix=%s")
+ if not ctx.attr.incompatible_normalize_name:
+ args.add("--noincompatible_normalize_name")
+ if not ctx.attr.incompatible_normalize_version:
+ args.add("--noincompatible_normalize_version")
# Pass workspace status files if stamping is enabled
if is_stamping_enabled(ctx.attr):
@@ -423,6 +499,7 @@ tries to locate `.runfiles` directory which is not packaged in the wheel.
),
},
_distribution_attrs,
+ _feature_flags,
_requirement_attrs,
_entrypoint_attrs,
_other_attrs,
@@ -432,7 +509,7 @@ tries to locate `.runfiles` directory which is not packaged in the wheel.
py_wheel = rule(
implementation = py_wheel_lib.implementation,
doc = """\
-Internal rule used by the [py_wheel macro](/docs/packaging.md#py_wheel).
+Internal rule used by the [py_wheel macro](#py_wheel).
These intentionally have the same name to avoid sharp edges with Bazel macros.
For example, a `bazel query` for a user's `py_wheel` macro expands to `py_wheel` targets,
diff --git a/python/private/py_wheel_normalize_pep440.bzl b/python/private/py_wheel_normalize_pep440.bzl
new file mode 100644
index 0000000..9566348
--- /dev/null
+++ b/python/private/py_wheel_normalize_pep440.bzl
@@ -0,0 +1,519 @@
+# 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.
+
+"Implementation of PEP440 version string normalization"
+
+def mkmethod(self, method):
+ """Bind a struct as the first arg to a function.
+
+ This is loosely equivalent to creating a bound method of a class.
+ """
+ return lambda *args, **kwargs: method(self, *args, **kwargs)
+
+def _isdigit(token):
+ return token.isdigit()
+
+def _isalnum(token):
+ return token.isalnum()
+
+def _lower(token):
+ # PEP 440: Case sensitivity
+ return token.lower()
+
+def _is(reference):
+ """Predicate testing a token for equality with `reference`."""
+ return lambda token: token == reference
+
+def _is_not(reference):
+ """Predicate testing a token for inequality with `reference`."""
+ return lambda token: token != reference
+
+def _in(reference):
+ """Predicate testing if a token is in the list `reference`."""
+ return lambda token: token in reference
+
+def _ctx(start):
+ return {"norm": "", "start": start}
+
+def _open_context(self):
+ """Open an new parsing ctx.
+
+ If the current parsing step succeeds, call self.accept().
+ If the current parsing step fails, call self.discard() to
+ go back to how it was before we opened a new ctx.
+
+ Args:
+ self: The normalizer.
+ """
+ self.contexts.append(_ctx(_context(self)["start"]))
+ return self.contexts[-1]
+
+def _accept(self):
+ """Close the current ctx successfully and merge the results."""
+ finished = self.contexts.pop()
+ self.contexts[-1]["norm"] += finished["norm"]
+ self.contexts[-1]["start"] = finished["start"]
+ return True
+
+def _context(self):
+ return self.contexts[-1]
+
+def _discard(self):
+ self.contexts.pop()
+ return False
+
+def _new(input):
+ """Create a new normalizer"""
+ self = struct(
+ input = input,
+ contexts = [_ctx(0)],
+ )
+
+ public = struct(
+ # methods: keep sorted
+ accept = mkmethod(self, _accept),
+ context = mkmethod(self, _context),
+ discard = mkmethod(self, _discard),
+ open_context = mkmethod(self, _open_context),
+
+ # attributes: keep sorted
+ input = self.input,
+ )
+ return public
+
+def accept(parser, predicate, value):
+ """If `predicate` matches the next token, accept the token.
+
+ Accepting the token means adding it (according to `value`) to
+ the running results maintained in ctx["norm"] and
+ advancing the cursor in ctx["start"] to the next token in
+ `version`.
+
+ Args:
+ parser: The normalizer.
+ predicate: function taking a token and returning a boolean
+ saying if we want to accept the token.
+ value: the string to add if there's a match, or, if `value`
+ is a function, the function to apply to the current token
+ to get the string to add.
+
+ Returns:
+ whether a token was accepted.
+ """
+
+ ctx = parser.context()
+
+ if ctx["start"] >= len(parser.input):
+ return False
+
+ token = parser.input[ctx["start"]]
+
+ if predicate(token):
+ if type(value) in ["function", "builtin_function_or_method"]:
+ value = value(token)
+
+ ctx["norm"] += value
+ ctx["start"] += 1
+ return True
+
+ return False
+
+def accept_placeholder(parser):
+ """Accept a Bazel placeholder.
+
+ Placeholders aren't actually part of PEP 440, but are used for
+ stamping purposes. A placeholder might be
+ ``{BUILD_TIMESTAMP}``, for instance. We'll accept these as
+ they are, assuming they will expand to something that makes
+ sense where they appear. Before the stamping has happened, a
+ resulting wheel file name containing a placeholder will not
+ actually be valid.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a placeholder was accepted.
+ """
+ ctx = parser.open_context()
+
+ if not accept(parser, _is("{"), str):
+ return parser.discard()
+
+ start = ctx["start"]
+ for _ in range(start, len(parser.input) + 1):
+ if not accept(parser, _is_not("}"), str):
+ break
+
+ if not accept(parser, _is("}"), str):
+ return parser.discard()
+
+ return parser.accept()
+
+def accept_digits(parser):
+ """Accept multiple digits (or placeholders).
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether some digits (or placeholders) were accepted.
+ """
+
+ ctx = parser.open_context()
+ start = ctx["start"]
+
+ for i in range(start, len(parser.input) + 1):
+ if not accept(parser, _isdigit, str) and not accept_placeholder(parser):
+ if i - start >= 1:
+ if ctx["norm"].isdigit():
+ # PEP 440: Integer Normalization
+ ctx["norm"] = str(int(ctx["norm"]))
+ return parser.accept()
+ break
+
+ return parser.discard()
+
+def accept_string(parser, string, replacement):
+ """Accept a `string` in the input. Output `replacement`.
+
+ Args:
+ parser: The normalizer.
+ string: The string to search for in the parser input.
+ replacement: The normalized string to use if the string was found.
+
+ Returns:
+ whether the string was accepted.
+ """
+ ctx = parser.open_context()
+
+ for character in string.elems():
+ if not accept(parser, _in([character, character.upper()]), ""):
+ return parser.discard()
+
+ ctx["norm"] = replacement
+
+ return parser.accept()
+
+def accept_alnum(parser):
+ """Accept an alphanumeric sequence.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether an alphanumeric sequence was accepted.
+ """
+
+ ctx = parser.open_context()
+ start = ctx["start"]
+
+ for i in range(start, len(parser.input) + 1):
+ if not accept(parser, _isalnum, _lower) and not accept_placeholder(parser):
+ if i - start >= 1:
+ return parser.accept()
+ break
+
+ return parser.discard()
+
+def accept_dot_number(parser):
+ """Accept a dot followed by digits.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a dot+digits pair was accepted.
+ """
+ parser.open_context()
+
+ if accept(parser, _is("."), ".") and accept_digits(parser):
+ return parser.accept()
+ else:
+ return parser.discard()
+
+def accept_dot_number_sequence(parser):
+ """Accept a sequence of dot+digits.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a sequence of dot+digits pairs was accepted.
+ """
+ ctx = parser.context()
+ start = ctx["start"]
+ i = start
+
+ for i in range(start, len(parser.input) + 1):
+ if not accept_dot_number(parser):
+ break
+ return i - start >= 1
+
+def accept_separator_alnum(parser):
+ """Accept a separator followed by an alphanumeric string.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a separator and an alphanumeric string were accepted.
+ """
+ parser.open_context()
+
+ # PEP 440: Local version segments
+ if (
+ accept(parser, _in([".", "-", "_"]), ".") and
+ (accept_digits(parser) or accept_alnum(parser))
+ ):
+ return parser.accept()
+
+ return parser.discard()
+
+def accept_separator_alnum_sequence(parser):
+ """Accept a sequence of separator+alphanumeric.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a sequence of separator+alphanumerics was accepted.
+ """
+ ctx = parser.context()
+ start = ctx["start"]
+ i = start
+
+ for i in range(start, len(parser.input) + 1):
+ if not accept_separator_alnum(parser):
+ break
+
+ return i - start >= 1
+
+def accept_epoch(parser):
+ """PEP 440: Version epochs.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a PEP 440 epoch identifier was accepted.
+ """
+ ctx = parser.open_context()
+ if accept_digits(parser) and accept(parser, _is("!"), "!"):
+ if ctx["norm"] == "0!":
+ ctx["norm"] = ""
+ return parser.accept()
+ else:
+ return parser.discard()
+
+def accept_release(parser):
+ """Accept the release segment, numbers separated by dots.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a release segment was accepted.
+ """
+ parser.open_context()
+
+ if not accept_digits(parser):
+ return parser.discard()
+
+ accept_dot_number_sequence(parser)
+ return parser.accept()
+
+def accept_pre_l(parser):
+ """PEP 440: Pre-release spelling.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a prerelease keyword was accepted.
+ """
+ parser.open_context()
+
+ if (
+ accept_string(parser, "alpha", "a") or
+ accept_string(parser, "a", "a") or
+ accept_string(parser, "beta", "b") or
+ accept_string(parser, "b", "b") or
+ accept_string(parser, "c", "rc") or
+ accept_string(parser, "preview", "rc") or
+ accept_string(parser, "pre", "rc") or
+ accept_string(parser, "rc", "rc")
+ ):
+ return parser.accept()
+ else:
+ return parser.discard()
+
+def accept_prerelease(parser):
+ """PEP 440: Pre-releases.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a prerelease identifier was accepted.
+ """
+ ctx = parser.open_context()
+
+ # PEP 440: Pre-release separators
+ accept(parser, _in(["-", "_", "."]), "")
+
+ if not accept_pre_l(parser):
+ return parser.discard()
+
+ accept(parser, _in(["-", "_", "."]), "")
+
+ if not accept_digits(parser):
+ # PEP 440: Implicit pre-release number
+ ctx["norm"] += "0"
+
+ return parser.accept()
+
+def accept_implicit_postrelease(parser):
+ """PEP 440: Implicit post releases.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether an implicit postrelease identifier was accepted.
+ """
+ ctx = parser.open_context()
+
+ if accept(parser, _is("-"), "") and accept_digits(parser):
+ ctx["norm"] = ".post" + ctx["norm"]
+ return parser.accept()
+
+ return parser.discard()
+
+def accept_explicit_postrelease(parser):
+ """PEP 440: Post-releases.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether an explicit postrelease identifier was accepted.
+ """
+ ctx = parser.open_context()
+
+ # PEP 440: Post release separators
+ if not accept(parser, _in(["-", "_", "."]), "."):
+ ctx["norm"] += "."
+
+ # PEP 440: Post release spelling
+ if (
+ accept_string(parser, "post", "post") or
+ accept_string(parser, "rev", "post") or
+ accept_string(parser, "r", "post")
+ ):
+ accept(parser, _in(["-", "_", "."]), "")
+
+ if not accept_digits(parser):
+ # PEP 440: Implicit post release number
+ ctx["norm"] += "0"
+
+ return parser.accept()
+
+ return parser.discard()
+
+def accept_postrelease(parser):
+ """PEP 440: Post-releases.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a postrelease identifier was accepted.
+ """
+ parser.open_context()
+
+ if accept_implicit_postrelease(parser) or accept_explicit_postrelease(parser):
+ return parser.accept()
+
+ return parser.discard()
+
+def accept_devrelease(parser):
+ """PEP 440: Developmental releases.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a developmental release identifier was accepted.
+ """
+ ctx = parser.open_context()
+
+ # PEP 440: Development release separators
+ if not accept(parser, _in(["-", "_", "."]), "."):
+ ctx["norm"] += "."
+
+ if accept_string(parser, "dev", "dev"):
+ accept(parser, _in(["-", "_", "."]), "")
+
+ if not accept_digits(parser):
+ # PEP 440: Implicit development release number
+ ctx["norm"] += "0"
+
+ return parser.accept()
+
+ return parser.discard()
+
+def accept_local(parser):
+ """PEP 440: Local version identifiers.
+
+ Args:
+ parser: The normalizer.
+
+ Returns:
+ whether a local version identifier was accepted.
+ """
+ parser.open_context()
+
+ if accept(parser, _is("+"), "+") and accept_alnum(parser):
+ accept_separator_alnum_sequence(parser)
+ return parser.accept()
+
+ return parser.discard()
+
+def normalize_pep440(version):
+ """Escape the version component of a filename.
+
+ See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
+ and https://peps.python.org/pep-0440/
+
+ Args:
+ version: version string to be normalized according to PEP 440.
+
+ Returns:
+ string containing the normalized version.
+ """
+ parser = _new(version.strip()) # PEP 440: Leading and Trailing Whitespace
+ accept(parser, _is("v"), "") # PEP 440: Preceding v character
+ accept_epoch(parser)
+ accept_release(parser)
+ accept_prerelease(parser)
+ accept_postrelease(parser)
+ accept_devrelease(parser)
+ accept_local(parser)
+ if parser.input[parser.context()["start"]:]:
+ fail(
+ "Failed to parse PEP 440 version identifier '%s'." % parser.input,
+ "Parse error at '%s'" % parser.input[parser.context()["start"]:],
+ )
+ return parser.context()["norm"]
diff --git a/python/private/python_bootstrap_template.txt b/python/private/python_bootstrap_template.txt
new file mode 100644
index 0000000..92dd6b8
--- /dev/null
+++ b/python/private/python_bootstrap_template.txt
@@ -0,0 +1,559 @@
+%shebang%
+
+# This script must retain compatibility with a wide variety of Python versions
+# since it is run for every py_binary target. Currently we guarantee support
+# going back to Python 2.7, and try to support even Python 2.6 on a best-effort
+# basis. We might abandon 2.6 support once users have the ability to control the
+# above shebang string via the Python toolchain (#8685).
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import sys
+
+# The Python interpreter unconditionally prepends the directory containing this
+# script (following symlinks) to the import path. This is the cause of #9239,
+# and is a special case of #7091. We therefore explicitly delete that entry.
+# TODO(#7091): Remove this hack when no longer necessary.
+del sys.path[0]
+
+import os
+import subprocess
+
+def IsRunningFromZip():
+ return %is_zipfile%
+
+if IsRunningFromZip():
+ import shutil
+ import tempfile
+ import zipfile
+else:
+ import re
+
+# Return True if running on Windows
+def IsWindows():
+ return os.name == 'nt'
+
+def GetWindowsPathWithUNCPrefix(path):
+ """Adds UNC prefix after getting a normalized absolute Windows path.
+
+ No-op for non-Windows platforms or if running under python2.
+ """
+ path = path.strip()
+
+ # No need to add prefix for non-Windows platforms.
+ # And \\?\ doesn't work in python 2 or on mingw
+ if not IsWindows() or sys.version_info[0] < 3:
+ return path
+
+ # Starting in Windows 10, version 1607(OS build 14393), MAX_PATH limitations have been
+ # removed from common Win32 file and directory functions.
+ # Related doc: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later
+ import platform
+ if platform.win32_ver()[1] >= '10.0.14393':
+ return path
+
+ # import sysconfig only now to maintain python 2.6 compatibility
+ import sysconfig
+ if sysconfig.get_platform() == 'mingw':
+ return path
+
+ # Lets start the unicode fun
+ unicode_prefix = '\\\\?\\'
+ if path.startswith(unicode_prefix):
+ return path
+
+ # os.path.abspath returns a normalized absolute path
+ return unicode_prefix + os.path.abspath(path)
+
+def HasWindowsExecutableExtension(path):
+ return path.endswith('.exe') or path.endswith('.com') or path.endswith('.bat')
+
+PYTHON_BINARY = '%python_binary%'
+if IsWindows() and not HasWindowsExecutableExtension(PYTHON_BINARY):
+ PYTHON_BINARY = PYTHON_BINARY + '.exe'
+
+def SearchPath(name):
+ """Finds a file in a given search path."""
+ search_path = os.getenv('PATH', os.defpath).split(os.pathsep)
+ for directory in search_path:
+ if directory:
+ path = os.path.join(directory, name)
+ if os.path.isfile(path) and os.access(path, os.X_OK):
+ return path
+ return None
+
+def FindPythonBinary(module_space):
+ """Finds the real Python binary if it's not a normal absolute path."""
+ return FindBinary(module_space, PYTHON_BINARY)
+
+def PrintVerboseCoverage(*args):
+ """Print output if VERBOSE_COVERAGE is non-empty in the environment."""
+ if os.environ.get("VERBOSE_COVERAGE"):
+ print(*args, file=sys.stderr)
+
+def FindCoverageEntryPoint(module_space):
+ cov_tool = '%coverage_tool%'
+ if cov_tool:
+ PrintVerboseCoverage('Using toolchain coverage_tool %r' % cov_tool)
+ else:
+ cov_tool = os.environ.get('PYTHON_COVERAGE')
+ if cov_tool:
+ PrintVerboseCoverage('PYTHON_COVERAGE: %r' % cov_tool)
+ if cov_tool:
+ return FindBinary(module_space, cov_tool)
+ return None
+
+def FindBinary(module_space, bin_name):
+ """Finds the real binary if it's not a normal absolute path."""
+ if not bin_name:
+ return None
+ if bin_name.startswith("//"):
+ # Case 1: Path is a label. Not supported yet.
+ raise AssertionError(
+ "Bazel does not support execution of Python interpreters via labels yet"
+ )
+ elif os.path.isabs(bin_name):
+ # Case 2: Absolute path.
+ return bin_name
+ # Use normpath() to convert slashes to os.sep on Windows.
+ elif os.sep in os.path.normpath(bin_name):
+ # Case 3: Path is relative to the repo root.
+ return os.path.join(module_space, bin_name)
+ else:
+ # Case 4: Path has to be looked up in the search path.
+ return SearchPath(bin_name)
+
+def CreatePythonPathEntries(python_imports, module_space):
+ parts = python_imports.split(':')
+ return [module_space] + ['%s/%s' % (module_space, path) for path in parts]
+
+def FindModuleSpace(main_rel_path):
+ """Finds the runfiles tree."""
+ # When the calling process used the runfiles manifest to resolve the
+ # location of this stub script, the path may be expanded. This means
+ # argv[0] may no longer point to a location inside the runfiles
+ # directory. We should therefore respect RUNFILES_DIR and
+ # RUNFILES_MANIFEST_FILE set by the caller.
+ runfiles_dir = os.environ.get('RUNFILES_DIR', None)
+ if not runfiles_dir:
+ runfiles_manifest_file = os.environ.get('RUNFILES_MANIFEST_FILE', '')
+ if (runfiles_manifest_file.endswith('.runfiles_manifest') or
+ runfiles_manifest_file.endswith('.runfiles/MANIFEST')):
+ runfiles_dir = runfiles_manifest_file[:-9]
+ # Be defensive: the runfiles dir should contain our main entry point. If
+ # it doesn't, then it must not be our runfiles directory.
+ if runfiles_dir and os.path.exists(os.path.join(runfiles_dir, main_rel_path)):
+ return runfiles_dir
+
+ stub_filename = sys.argv[0]
+ if not os.path.isabs(stub_filename):
+ stub_filename = os.path.join(os.getcwd(), stub_filename)
+
+ while True:
+ module_space = stub_filename + ('.exe' if IsWindows() else '') + '.runfiles'
+ if os.path.isdir(module_space):
+ return module_space
+
+ runfiles_pattern = r'(.*\.runfiles)' + (r'\\' if IsWindows() else '/') + '.*'
+ matchobj = re.match(runfiles_pattern, stub_filename)
+ if matchobj:
+ return matchobj.group(1)
+
+ if not os.path.islink(stub_filename):
+ break
+ target = os.readlink(stub_filename)
+ if os.path.isabs(target):
+ stub_filename = target
+ else:
+ stub_filename = os.path.join(os.path.dirname(stub_filename), target)
+
+ raise AssertionError('Cannot find .runfiles directory for %s' % sys.argv[0])
+
+def ExtractZip(zip_path, dest_dir):
+ """Extracts the contents of a zip file, preserving the unix file mode bits.
+
+ These include the permission bits, and in particular, the executable bit.
+
+ Ideally the zipfile module should set these bits, but it doesn't. See:
+ https://bugs.python.org/issue15795.
+
+ Args:
+ zip_path: The path to the zip file to extract
+ dest_dir: The path to the destination directory
+ """
+ zip_path = GetWindowsPathWithUNCPrefix(zip_path)
+ dest_dir = GetWindowsPathWithUNCPrefix(dest_dir)
+ with zipfile.ZipFile(zip_path) as zf:
+ for info in zf.infolist():
+ zf.extract(info, dest_dir)
+ # UNC-prefixed paths must be absolute/normalized. See
+ # https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation
+ file_path = os.path.abspath(os.path.join(dest_dir, info.filename))
+ # The Unix st_mode bits (see "man 7 inode") are stored in the upper 16
+ # bits of external_attr. Of those, we set the lower 12 bits, which are the
+ # file mode bits (since the file type bits can't be set by chmod anyway).
+ attrs = info.external_attr >> 16
+ if attrs != 0: # Rumor has it these can be 0 for zips created on Windows.
+ os.chmod(file_path, attrs & 0o7777)
+
+# Create the runfiles tree by extracting the zip file
+def CreateModuleSpace():
+ temp_dir = tempfile.mkdtemp('', 'Bazel.runfiles_')
+ ExtractZip(os.path.dirname(__file__), temp_dir)
+ # IMPORTANT: Later code does `rm -fr` on dirname(module_space) -- it's
+ # important that deletion code be in sync with this directory structure
+ return os.path.join(temp_dir, 'runfiles')
+
+# Returns repository roots to add to the import path.
+def GetRepositoriesImports(module_space, import_all):
+ if import_all:
+ repo_dirs = [os.path.join(module_space, d) for d in os.listdir(module_space)]
+ repo_dirs.sort()
+ return [d for d in repo_dirs if os.path.isdir(d)]
+ return [os.path.join(module_space, '%workspace_name%')]
+
+def RunfilesEnvvar(module_space):
+ """Finds the runfiles manifest or the runfiles directory.
+
+ Returns:
+ A tuple of (var_name, var_value) where var_name is either 'RUNFILES_DIR' or
+ 'RUNFILES_MANIFEST_FILE' and var_value is the path to that directory or
+ file, or (None, None) if runfiles couldn't be found.
+ """
+ # If this binary is the data-dependency of another one, the other sets
+ # RUNFILES_MANIFEST_FILE or RUNFILES_DIR for our sake.
+ runfiles = os.environ.get('RUNFILES_MANIFEST_FILE', None)
+ if runfiles:
+ return ('RUNFILES_MANIFEST_FILE', runfiles)
+
+ runfiles = os.environ.get('RUNFILES_DIR', None)
+ if runfiles:
+ return ('RUNFILES_DIR', runfiles)
+
+ # If running from a zip, there's no manifest file.
+ if IsRunningFromZip():
+ return ('RUNFILES_DIR', module_space)
+
+ # Look for the runfiles "output" manifest, argv[0] + ".runfiles_manifest"
+ runfiles = module_space + '_manifest'
+ if os.path.exists(runfiles):
+ return ('RUNFILES_MANIFEST_FILE', runfiles)
+
+ # Look for the runfiles "input" manifest, argv[0] + ".runfiles/MANIFEST"
+ # Normally .runfiles_manifest and MANIFEST are both present, but the
+ # former will be missing for zip-based builds or if someone copies the
+ # runfiles tree elsewhere.
+ runfiles = os.path.join(module_space, 'MANIFEST')
+ if os.path.exists(runfiles):
+ return ('RUNFILES_MANIFEST_FILE', runfiles)
+
+ # If running in a sandbox and no environment variables are set, then
+ # Look for the runfiles next to the binary.
+ if module_space.endswith('.runfiles') and os.path.isdir(module_space):
+ return ('RUNFILES_DIR', module_space)
+
+ return (None, None)
+
+def Deduplicate(items):
+ """Efficiently filter out duplicates, keeping the first element only."""
+ seen = set()
+ for it in items:
+ if it not in seen:
+ seen.add(it)
+ yield it
+
+def InstrumentedFilePaths():
+ """Yields tuples of realpath of each instrumented file with the relative path."""
+ manifest_filename = os.environ.get('COVERAGE_MANIFEST')
+ if not manifest_filename:
+ return
+ with open(manifest_filename, "r") as manifest:
+ for line in manifest:
+ filename = line.strip()
+ if not filename:
+ continue
+ try:
+ realpath = os.path.realpath(filename)
+ except OSError:
+ print(
+ "Could not find instrumented file {}".format(filename),
+ file=sys.stderr)
+ continue
+ if realpath != filename:
+ PrintVerboseCoverage("Fixing up {} -> {}".format(realpath, filename))
+ yield (realpath, filename)
+
+def UnresolveSymlinks(output_filename):
+ # type: (str) -> None
+ """Replace realpath of instrumented files with the relative path in the lcov output.
+
+ Though we are asking coveragepy to use relative file names, currently
+ ignore that for purposes of generating the lcov report (and other reports
+ which are not the XML report), so we need to go and fix up the report.
+
+ This function is a workaround for that issue. Once that issue is fixed
+ upstream and the updated version is widely in use, this should be removed.
+
+ See https://github.com/nedbat/coveragepy/issues/963.
+ """
+ substitutions = list(InstrumentedFilePaths())
+ if substitutions:
+ unfixed_file = output_filename + '.tmp'
+ os.rename(output_filename, unfixed_file)
+ with open(unfixed_file, "r") as unfixed:
+ with open(output_filename, "w") as output_file:
+ for line in unfixed:
+ if line.startswith('SF:'):
+ for (realpath, filename) in substitutions:
+ line = line.replace(realpath, filename)
+ output_file.write(line)
+ os.unlink(unfixed_file)
+
+def ExecuteFile(python_program, main_filename, args, env, module_space,
+ coverage_entrypoint, workspace, delete_module_space):
+ # type: (str, str, list[str], dict[str, str], str, str|None, str|None) -> ...
+ """Executes the given Python file using the various environment settings.
+
+ This will not return, and acts much like os.execv, except is much
+ more restricted, and handles Bazel-related edge cases.
+
+ Args:
+ python_program: (str) Path to the Python binary to use for execution
+ main_filename: (str) The Python file to execute
+ args: (list[str]) Additional args to pass to the Python file
+ env: (dict[str, str]) A dict of environment variables to set for the execution
+ module_space: (str) Path to the module space/runfiles tree directory
+ coverage_entrypoint: (str|None) Path to the coverage tool entry point file.
+ workspace: (str|None) Name of the workspace to execute in. This is expected to be a
+ directory under the runfiles tree.
+ delete_module_space: (bool), True if the module space should be deleted
+ after a successful (exit code zero) program run, False if not.
+ """
+ # We want to use os.execv instead of subprocess.call, which causes
+ # problems with signal passing (making it difficult to kill
+ # Bazel). However, these conditions force us to run via
+ # subprocess.call instead:
+ #
+ # - On Windows, os.execv doesn't handle arguments with spaces
+ # correctly, and it actually starts a subprocess just like
+ # subprocess.call.
+ # - When running in a workspace or zip file, we need to clean up the
+ # workspace after the process finishes so control must return here.
+ # - If we may need to emit a host config warning after execution, we
+ # can't execv because we need control to return here. This only
+ # happens for targets built in the host config.
+ # - For coverage targets, at least coveragepy requires running in
+ # two invocations, which also requires control to return here.
+ #
+ if not (IsWindows() or workspace or coverage_entrypoint or delete_module_space):
+ _RunExecv(python_program, main_filename, args, env)
+
+ if coverage_entrypoint is not None:
+ ret_code = _RunForCoverage(python_program, main_filename, args, env,
+ coverage_entrypoint, workspace)
+ else:
+ ret_code = subprocess.call(
+ [python_program, main_filename] + args,
+ env=env,
+ cwd=workspace
+ )
+
+ if delete_module_space:
+ # NOTE: dirname() is called because CreateModuleSpace() creates a
+ # sub-directory within a temporary directory, and we want to remove the
+ # whole temporary directory.
+ shutil.rmtree(os.path.dirname(module_space), True)
+ sys.exit(ret_code)
+
+def _RunExecv(python_program, main_filename, args, env):
+ # type: (str, str, list[str], dict[str, str]) -> ...
+ """Executes the given Python file using the various environment settings."""
+ os.environ.update(env)
+ os.execv(python_program, [python_program, main_filename] + args)
+
+def _RunForCoverage(python_program, main_filename, args, env,
+ coverage_entrypoint, workspace):
+ # type: (str, str, list[str], dict[str, str], str, str|None) -> int
+ """Collects coverage infomration for the given Python file.
+
+ Args:
+ python_program: (str) Path to the Python binary to use for execution
+ main_filename: (str) The Python file to execute
+ args: (list[str]) Additional args to pass to the Python file
+ env: (dict[str, str]) A dict of environment variables to set for the execution
+ coverage_entrypoint: (str|None) Path to the coverage entry point to execute with.
+ workspace: (str|None) Name of the workspace to execute in. This is expected to be a
+ directory under the runfiles tree, and will recursively delete the
+ runfiles directory if set.
+ """
+ # We need for coveragepy to use relative paths. This can only be configured
+ # via an rc file, so we need to make one.
+ rcfile_name = os.path.join(os.environ['COVERAGE_DIR'], '.coveragerc')
+ with open(rcfile_name, "w") as rcfile:
+ rcfile.write('''[run]
+relative_files = True
+''')
+ PrintVerboseCoverage('Coverage entrypoint:', coverage_entrypoint)
+ # First run the target Python file via coveragepy to create a .coverage
+ # database file, from which we can later export lcov.
+ ret_code = subprocess.call(
+ [
+ python_program,
+ coverage_entrypoint,
+ "run",
+ "--rcfile=" + rcfile_name,
+ "--append",
+ "--branch",
+ main_filename
+ ] + args,
+ env=env,
+ cwd=workspace
+ )
+ output_filename = os.path.join(os.environ['COVERAGE_DIR'], 'pylcov.dat')
+
+ PrintVerboseCoverage('Converting coveragepy database to lcov:', output_filename)
+ # Run coveragepy again to convert its .coverage database file into lcov.
+ ret_code = subprocess.call(
+ [
+ python_program,
+ coverage_entrypoint,
+ "lcov",
+ "--rcfile=" + rcfile_name,
+ "-o",
+ output_filename
+ ],
+ env=env,
+ cwd=workspace
+ ) or ret_code
+ try:
+ os.unlink(rcfile_name)
+ except OSError as err:
+ # It's possible that the profiled program might execute another Python
+ # binary through a wrapper that would then delete the rcfile. Not much
+ # we can do about that, besides ignore the failure here.
+ PrintVerboseCoverage('Error removing temporary coverage rc file:', err)
+ if os.path.isfile(output_filename):
+ UnresolveSymlinks(output_filename)
+ return ret_code
+
+def Main():
+ args = sys.argv[1:]
+
+ new_env = {}
+
+ # The main Python source file.
+ # The magic string percent-main-percent is replaced with the runfiles-relative
+ # filename of the main file of the Python binary in BazelPythonSemantics.java.
+ main_rel_path = '%main%'
+ if IsWindows():
+ main_rel_path = main_rel_path.replace('/', os.sep)
+
+ if IsRunningFromZip():
+ module_space = CreateModuleSpace()
+ delete_module_space = True
+ else:
+ module_space = FindModuleSpace(main_rel_path)
+ delete_module_space = False
+
+ python_imports = '%imports%'
+ python_path_entries = CreatePythonPathEntries(python_imports, module_space)
+ python_path_entries += GetRepositoriesImports(module_space, %import_all%)
+ # Remove duplicates to avoid overly long PYTHONPATH (#10977). Preserve order,
+ # keep first occurrence only.
+ python_path_entries = [
+ GetWindowsPathWithUNCPrefix(d)
+ for d in python_path_entries
+ ]
+
+ old_python_path = os.environ.get('PYTHONPATH')
+ if old_python_path:
+ python_path_entries += old_python_path.split(os.pathsep)
+
+ python_path = os.pathsep.join(Deduplicate(python_path_entries))
+
+ if IsWindows():
+ python_path = python_path.replace('/', os.sep)
+
+ new_env['PYTHONPATH'] = python_path
+ runfiles_envkey, runfiles_envvalue = RunfilesEnvvar(module_space)
+ if runfiles_envkey:
+ new_env[runfiles_envkey] = runfiles_envvalue
+
+ # Don't prepend a potentially unsafe path to sys.path
+ # See: https://docs.python.org/3.11/using/cmdline.html#envvar-PYTHONSAFEPATH
+ new_env['PYTHONSAFEPATH'] = '1'
+
+ main_filename = os.path.join(module_space, main_rel_path)
+ main_filename = GetWindowsPathWithUNCPrefix(main_filename)
+ assert os.path.exists(main_filename), \
+ 'Cannot exec() %r: file not found.' % main_filename
+ assert os.access(main_filename, os.R_OK), \
+ 'Cannot exec() %r: file not readable.' % main_filename
+
+ program = python_program = FindPythonBinary(module_space)
+ if python_program is None:
+ raise AssertionError('Could not find python binary: ' + PYTHON_BINARY)
+
+ # COVERAGE_DIR is set if coverage is enabled and instrumentation is configured
+ # for something, though it could be another program executing this one or
+ # one executed by this one (e.g. an extension module).
+ if os.environ.get('COVERAGE_DIR'):
+ cov_tool = FindCoverageEntryPoint(module_space)
+ if cov_tool is None:
+ PrintVerboseCoverage('Coverage was enabled, but python coverage tool was not configured.')
+ else:
+ # Inhibit infinite recursion:
+ if 'PYTHON_COVERAGE' in os.environ:
+ del os.environ['PYTHON_COVERAGE']
+
+ if not os.path.exists(cov_tool):
+ raise EnvironmentError(
+ 'Python coverage tool %r not found. '
+ 'Try running with VERBOSE_COVERAGE=1 to collect more information.'
+ % cov_tool
+ )
+
+ # coverage library expects sys.path[0] to contain the library, and replaces
+ # it with the directory of the program it starts. Our actual sys.path[0] is
+ # the runfiles directory, which must not be replaced.
+ # CoverageScript.do_execute() undoes this sys.path[0] setting.
+ #
+ # Update sys.path such that python finds the coverage package. The coverage
+ # entry point is coverage.coverage_main, so we need to do twice the dirname.
+ python_path_entries = new_env['PYTHONPATH'].split(os.pathsep)
+ python_path_entries.append(os.path.dirname(os.path.dirname(cov_tool)))
+ new_env['PYTHONPATH'] = os.pathsep.join(Deduplicate(python_path_entries))
+ else:
+ cov_tool = None
+
+ new_env.update((key, val) for key, val in os.environ.items() if key not in new_env)
+
+ workspace = None
+ if IsRunningFromZip():
+ # If RUN_UNDER_RUNFILES equals 1, it means we need to
+ # change directory to the right runfiles directory.
+ # (So that the data files are accessible)
+ if os.environ.get('RUN_UNDER_RUNFILES') == '1':
+ workspace = os.path.join(module_space, '%workspace_name%')
+
+ try:
+ sys.stdout.flush()
+ # NOTE: ExecuteFile may call execve() and lines after this will never run.
+ ExecuteFile(
+ python_program, main_filename, args, new_env, module_space,
+ cov_tool, workspace,
+ delete_module_space = delete_module_space,
+ )
+
+ except EnvironmentError:
+ # This works from Python 2.4 all the way to 3.x.
+ e = sys.exc_info()[1]
+ # This exception occurs when os.execv() fails for some reason.
+ if not getattr(e, 'filename', None):
+ e.filename = program # Add info to error message
+ raise
+
+if __name__ == '__main__':
+ Main()
diff --git a/python/private/reexports.bzl b/python/private/reexports.bzl
index a300a20..ea39ac9 100644
--- a/python/private/reexports.bzl
+++ b/python/private/reexports.bzl
@@ -12,20 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Internal re-exports of built-in symbols.
+"""Internal re-exports of builtin symbols.
-Currently the definitions here are re-exports of the native rules, "blessed" to
-work under `--incompatible_load_python_rules_from_bzl`. As the native rules get
-migrated to Starlark, their implementations will be removed from here.
+We want to use both the PyInfo defined by builtins and the one defined by
+rules_python. Because the builtin symbol is going away, the rules_python
+PyInfo symbol is given preference. Unfortunately, that masks the builtin,
+so we have to rebind it to another name and load it to make it available again.
-We want to re-export a built-in symbol as if it were defined in a Starlark
-file, so that users can for instance do:
-
-```
-load("@rules_python//python:defs.bzl", "PyInfo")
-```
-
-Unfortunately, we can't just write in defs.bzl
+Unfortunately, we can't just write:
```
PyInfo = PyInfo
@@ -33,15 +27,14 @@ PyInfo = PyInfo
because the declaration of module-level symbol `PyInfo` makes the builtin
inaccessible. So instead we access the builtin here and export it under a
-different name. Then we can load it from defs.bzl and export it there under
-the original name.
+different name. Then we can load it from elsewhere.
"""
# Don't use underscore prefix, since that would make the symbol local to this
# file only. Use a non-conventional name to emphasize that this is not a public
# symbol.
# buildifier: disable=name-conventions
-internal_PyInfo = PyInfo
+BuiltinPyInfo = PyInfo
# buildifier: disable=name-conventions
-internal_PyRuntimeInfo = PyRuntimeInfo
+BuiltinPyRuntimeInfo = PyRuntimeInfo
diff --git a/python/private/register_extension_info.bzl b/python/private/register_extension_info.bzl
new file mode 100644
index 0000000..408df62
--- /dev/null
+++ b/python/private/register_extension_info.bzl
@@ -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.
+"""Stub implementation to make patching easier."""
+
+# buildifier: disable=unused-variable
+def register_extension_info(**kwargs):
+ """A no-op stub to make Google patching easier."""
diff --git a/python/private/render_pkg_aliases.bzl b/python/private/render_pkg_aliases.bzl
new file mode 100644
index 0000000..9ebbc36
--- /dev/null
+++ b/python/private/render_pkg_aliases.bzl
@@ -0,0 +1,190 @@
+# 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.
+
+"""render_pkg_aliases is a function to generate BUILD.bazel contents used to create user-friendly aliases.
+
+This is used in bzlmod and non-bzlmod setups."""
+
+load("//python/private:normalize_name.bzl", "normalize_name")
+load(":text_util.bzl", "render")
+load(":version_label.bzl", "version_label")
+
+NO_MATCH_ERROR_MESSAGE_TEMPLATE = """\
+No matching wheel for current configuration's Python version.
+
+The current build configuration's Python version doesn't match any of the Python
+versions available for this wheel. This wheel supports the following Python versions:
+ {supported_versions}
+
+As matched by the `@{rules_python}//python/config_settings:is_python_<version>`
+configuration settings.
+
+To determine the current configuration's Python version, run:
+ `bazel config <config id>` (shown further below)
+and look for
+ {rules_python}//python/config_settings:python_version
+
+If the value is missing, then the "default" Python version is being used,
+which has a "null" version value and will not match version constraints.
+"""
+
+def _render_whl_library_alias(
+ *,
+ name,
+ repo_name,
+ dep,
+ target,
+ default_version,
+ versions,
+ rules_python):
+ """Render an alias for common targets
+
+ If the versions is passed, then the `rules_python` must be passed as well and
+ an alias with a select statement based on the python version is going to be
+ generated.
+ """
+ if versions == None:
+ return render.alias(
+ name = name,
+ actual = repr("@{repo_name}_{dep}//:{target}".format(
+ repo_name = repo_name,
+ dep = dep,
+ target = target,
+ )),
+ )
+
+ # Create the alias repositories which contains different select
+ # statements These select statements point to the different pip
+ # whls that are based on a specific version of Python.
+ selects = {}
+ for full_version in versions:
+ condition = "@@{rules_python}//python/config_settings:is_python_{full_python_version}".format(
+ rules_python = rules_python,
+ full_python_version = full_version,
+ )
+ actual = "@{repo_name}_{version}_{dep}//:{target}".format(
+ repo_name = repo_name,
+ version = version_label(full_version),
+ dep = dep,
+ target = target,
+ )
+ selects[condition] = actual
+
+ if default_version:
+ no_match_error = None
+ default_actual = "@{repo_name}_{version}_{dep}//:{target}".format(
+ repo_name = repo_name,
+ version = version_label(default_version),
+ dep = dep,
+ target = target,
+ )
+ selects["//conditions:default"] = default_actual
+ else:
+ no_match_error = "_NO_MATCH_ERROR"
+
+ return render.alias(
+ name = name,
+ actual = render.select(
+ selects,
+ no_match_error = no_match_error,
+ ),
+ )
+
+def _render_common_aliases(repo_name, name, versions = None, default_version = None, rules_python = None):
+ lines = [
+ """package(default_visibility = ["//visibility:public"])""",
+ ]
+
+ if versions:
+ versions = sorted(versions)
+
+ if not versions:
+ pass
+ elif default_version in versions:
+ pass
+ else:
+ error_msg = NO_MATCH_ERROR_MESSAGE_TEMPLATE.format(
+ supported_versions = ", ".join(versions),
+ rules_python = rules_python,
+ )
+
+ lines.append("_NO_MATCH_ERROR = \"\"\"\\\n{error_msg}\"\"\"".format(
+ error_msg = error_msg,
+ ))
+
+ # This is to simplify the code in _render_whl_library_alias and to ensure
+ # that we don't pass a 'default_version' that is not in 'versions'.
+ default_version = None
+
+ lines.append(
+ render.alias(
+ name = name,
+ actual = repr(":pkg"),
+ ),
+ )
+ lines.extend(
+ [
+ _render_whl_library_alias(
+ name = target,
+ repo_name = repo_name,
+ dep = name,
+ target = target,
+ versions = versions,
+ default_version = default_version,
+ rules_python = rules_python,
+ )
+ for target in ["pkg", "whl", "data", "dist_info"]
+ ],
+ )
+
+ return "\n\n".join(lines)
+
+def render_pkg_aliases(*, repo_name, bzl_packages = None, whl_map = None, rules_python = None, default_version = None):
+ """Create alias declarations for each PyPI package.
+
+ The aliases should be appended to the pip_repository BUILD.bazel file. These aliases
+ allow users to use requirement() without needed a corresponding `use_repo()` for each dep
+ when using bzlmod.
+
+ Args:
+ repo_name: the repository name of the hub repository that is visible to the users that is
+ also used as the prefix for the spoke repo names (e.g. "pip", "pypi").
+ bzl_packages: the list of packages to setup, if not specified, whl_map.keys() will be used instead.
+ whl_map: the whl_map for generating Python version aware aliases.
+ default_version: the default version to be used for the aliases.
+ rules_python: the name of the rules_python workspace.
+
+ Returns:
+ A dict of file paths and their contents.
+ """
+ if not bzl_packages and whl_map:
+ bzl_packages = list(whl_map.keys())
+
+ contents = {}
+ for name in bzl_packages:
+ versions = None
+ if whl_map != None:
+ versions = whl_map[name]
+ name = normalize_name(name)
+
+ filename = "{}/BUILD.bazel".format(name)
+ contents[filename] = _render_common_aliases(
+ repo_name = repo_name,
+ name = name,
+ versions = versions,
+ rules_python = rules_python,
+ default_version = default_version,
+ ).strip()
+
+ return contents
diff --git a/python/private/repack_whl.py b/python/private/repack_whl.py
new file mode 100644
index 0000000..be113ef
--- /dev/null
+++ b/python/private/repack_whl.py
@@ -0,0 +1,182 @@
+# 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.
+
+"""
+Regenerate a whl file after patching and cleanup the patched contents.
+
+This script will take contents of the current directory and create a new wheel
+out of it and will remove all files that were written to the wheel.
+"""
+
+from __future__ import annotations
+
+import argparse
+import difflib
+import logging
+import pathlib
+import sys
+import tempfile
+
+from tools.wheelmaker import _WhlFile
+
+# NOTE: Implement the following matching of what goes into the RECORD
+# https://peps.python.org/pep-0491/#the-dist-info-directory
+_EXCLUDES = [
+ "RECORD",
+ "INSTALLER",
+ "RECORD.jws",
+ "RECORD.p7s",
+ "REQUESTED",
+]
+
+_DISTINFO = "dist-info"
+
+
+def _unidiff_output(expected, actual, record):
+ """
+ Helper function. Returns a string containing the unified diff of two
+ multiline strings.
+ """
+
+ expected = expected.splitlines(1)
+ actual = actual.splitlines(1)
+
+ diff = difflib.unified_diff(
+ expected, actual, fromfile=f"a/{record}", tofile=f"b/{record}"
+ )
+
+ return "".join(diff)
+
+
+def _files_to_pack(dir: pathlib.Path, want_record: str) -> list[pathlib.Path]:
+ """Check that the RECORD file entries are correct and print a unified diff on failure."""
+
+ # First get existing files by using the RECORD file
+ got_files = []
+ got_distinfos = []
+ for line in want_record.splitlines():
+ rec, _, _ = line.partition(",")
+ path = dir / rec
+
+ if not path.exists():
+ # skip files that do not exist as they won't be present in the final
+ # RECORD file.
+ continue
+
+ if not path.parent.name.endswith(_DISTINFO):
+ got_files.append(path)
+ elif path.name not in _EXCLUDES:
+ got_distinfos.append(path)
+
+ # Then get extra files present in the directory but not in the RECORD file
+ extra_files = []
+ extra_distinfos = []
+ for path in dir.rglob("*"):
+ if path.is_dir():
+ continue
+
+ elif path.parent.name.endswith(_DISTINFO):
+ if path.name in _EXCLUDES:
+ # NOTE: we implement the following matching of what goes into the RECORD
+ # https://peps.python.org/pep-0491/#the-dist-info-directory
+ continue
+ elif path not in got_distinfos:
+ extra_distinfos.append(path)
+
+ elif path not in got_files:
+ extra_files.append(path)
+
+ # sort the extra files for reproducibility
+ extra_files.sort()
+ extra_distinfos.sort()
+
+ # This order ensures that the structure of the RECORD file is always the
+ # same and ensures smaller patchsets to the RECORD file in general
+ return got_files + extra_files + got_distinfos + extra_distinfos
+
+
+def main(sys_argv):
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "whl_path",
+ type=pathlib.Path,
+ help="The original wheel file that we have patched.",
+ )
+ parser.add_argument(
+ "--record-patch",
+ type=pathlib.Path,
+ help="The output path that we are going to write the RECORD file patch to.",
+ )
+ parser.add_argument(
+ "output",
+ type=pathlib.Path,
+ help="The output path that we are going to write a new file to.",
+ )
+ args = parser.parse_args(sys_argv)
+
+ cwd = pathlib.Path.cwd()
+ logging.debug("=" * 80)
+ logging.debug("Repackaging the wheel")
+ logging.debug("=" * 80)
+
+ with tempfile.TemporaryDirectory(dir=cwd) as tmpdir:
+ patched_wheel_dir = cwd / tmpdir
+ logging.debug(f"Created a tmpdir: {patched_wheel_dir}")
+
+ excludes = [args.whl_path, patched_wheel_dir]
+
+ logging.debug("Moving whl contents to the newly created tmpdir")
+ for p in cwd.glob("*"):
+ if p in excludes:
+ logging.debug(f"Ignoring: {p}")
+ continue
+
+ rel_path = p.relative_to(cwd)
+ dst = p.rename(patched_wheel_dir / rel_path)
+ logging.debug(f"mv {p} -> {dst}")
+
+ distinfo_dir = next(iter(patched_wheel_dir.glob("*dist-info")))
+ logging.debug(f"Found dist-info dir: {distinfo_dir}")
+ record_path = distinfo_dir / "RECORD"
+ record_contents = record_path.read_text() if record_path.exists() else ""
+
+ with _WhlFile(args.output, mode="w", distinfo_dir=distinfo_dir) as out:
+ for p in _files_to_pack(patched_wheel_dir, record_contents):
+ rel_path = p.relative_to(patched_wheel_dir)
+ out.add_file(str(rel_path), p)
+
+ logging.debug(f"Writing RECORD file")
+ got_record = out.add_recordfile().decode("utf-8", "surrogateescape")
+
+ if got_record == record_contents:
+ logging.info(f"Created a whl file: {args.output}")
+ return
+
+ record_diff = _unidiff_output(
+ record_contents,
+ got_record,
+ out.distinfo_path("RECORD"),
+ )
+ args.record_patch.write_text(record_diff)
+ logging.warning(
+ f"Please apply patch to the RECORD file ({args.record_patch}):\n{record_diff}"
+ )
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ format="%(module)s: %(levelname)s: %(message)s", level=logging.DEBUG
+ )
+
+ sys.exit(main(sys.argv[1:]))
diff --git a/python/private/text_util.bzl b/python/private/text_util.bzl
new file mode 100644
index 0000000..78f62be
--- /dev/null
+++ b/python/private/text_util.bzl
@@ -0,0 +1,89 @@
+# 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.
+
+"""Text manipulation utilities useful for repository rule writing."""
+
+def _indent(text, indent = " " * 4):
+ if "\n" not in text:
+ return indent + text
+
+ return "\n".join([indent + line for line in text.splitlines()])
+
+def _render_alias(name, actual, *, visibility = None):
+ args = [
+ "name = \"{}\",".format(name),
+ "actual = {},".format(actual),
+ ]
+
+ if visibility:
+ args.append("visibility = {},".format(render.list(visibility)))
+
+ return "\n".join([
+ "alias(",
+ ] + [_indent(arg) for arg in args] + [
+ ")",
+ ])
+
+def _render_dict(d, *, value_repr = repr):
+ return "\n".join([
+ "{",
+ _indent("\n".join([
+ "{}: {},".format(repr(k), value_repr(v))
+ for k, v in d.items()
+ ])),
+ "}",
+ ])
+
+def _render_select(selects, *, no_match_error = None, value_repr = repr):
+ dict_str = _render_dict(selects, value_repr = value_repr) + ","
+
+ if no_match_error:
+ args = "\n".join([
+ "",
+ _indent(dict_str),
+ _indent("no_match_error = {},".format(no_match_error)),
+ "",
+ ])
+ else:
+ args = "\n".join([
+ "",
+ _indent(dict_str),
+ "",
+ ])
+
+ return "select({})".format(args)
+
+def _render_list(items):
+ if not items:
+ return "[]"
+
+ if len(items) == 1:
+ return "[{}]".format(repr(items[0]))
+
+ return "\n".join([
+ "[",
+ _indent("\n".join([
+ "{},".format(repr(item))
+ for item in items
+ ])),
+ "]",
+ ])
+
+render = struct(
+ alias = _render_alias,
+ dict = _render_dict,
+ indent = _indent,
+ list = _render_list,
+ select = _render_select,
+)
diff --git a/python/private/toolchains_repo.bzl b/python/private/toolchains_repo.bzl
index 5923787..4b6bd11 100644
--- a/python/private/toolchains_repo.bzl
+++ b/python/private/toolchains_repo.bzl
@@ -30,6 +30,7 @@ load(
"PLATFORMS",
"WINDOWS_NAME",
)
+load(":which.bzl", "which_with_fail")
def get_repository_name(repository_workspace):
dummy_label = "//:_"
@@ -154,22 +155,27 @@ def _toolchain_aliases_impl(rctx):
build_contents = """\
# Generated by python/private/toolchains_repo.bzl
package(default_visibility = ["//visibility:public"])
-load("@rules_python//python:versions.bzl", "PLATFORMS", "gen_python_config_settings")
+load("@rules_python//python:versions.bzl", "gen_python_config_settings")
gen_python_config_settings()
exports_files(["defs.bzl"])
-alias(name = "files", actual = select({{":" + item: "@{py_repository}_" + item + "//:files" for item in PLATFORMS.keys()}}))
-alias(name = "includes", actual = select({{":" + item: "@{py_repository}_" + item + "//:includes" for item in PLATFORMS.keys()}}))
-alias(name = "libpython", actual = select({{":" + item: "@{py_repository}_" + item + "//:libpython" for item in PLATFORMS.keys()}}))
-alias(name = "py3_runtime", actual = select({{":" + item: "@{py_repository}_" + item + "//:py3_runtime" for item in PLATFORMS.keys()}}))
-alias(name = "python_headers", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_headers" for item in PLATFORMS.keys()}}))
-alias(name = "python_runtimes", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_runtimes" for item in PLATFORMS.keys()}}))
-alias(name = "python3", actual = select({{":" + item: "@{py_repository}_" + item + "//:" + ("python.exe" if "windows" in item else "bin/python3") for item in PLATFORMS.keys()}}))
+
+PLATFORMS = [
+{loaded_platforms}
+]
+alias(name = "files", actual = select({{":" + item: "@{py_repository}_" + item + "//:files" for item in PLATFORMS}}))
+alias(name = "includes", actual = select({{":" + item: "@{py_repository}_" + item + "//:includes" for item in PLATFORMS}}))
+alias(name = "libpython", actual = select({{":" + item: "@{py_repository}_" + item + "//:libpython" for item in PLATFORMS}}))
+alias(name = "py3_runtime", actual = select({{":" + item: "@{py_repository}_" + item + "//:py3_runtime" for item in PLATFORMS}}))
+alias(name = "python_headers", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_headers" for item in PLATFORMS}}))
+alias(name = "python_runtimes", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_runtimes" for item in PLATFORMS}}))
+alias(name = "python3", actual = select({{":" + item: "@{py_repository}_" + item + "//:" + ("python.exe" if "windows" in item else "bin/python3") for item in PLATFORMS}}))
""".format(
py_repository = rctx.attr.user_repository_name,
+ loaded_platforms = "\n".join([" \"{}\",".format(p) for p in rctx.attr.platforms]),
)
if not is_windows:
build_contents += """\
-alias(name = "pip", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_runtimes" for item in PLATFORMS.keys() if "windows" not in item}}))
+alias(name = "pip", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_runtimes" for item in PLATFORMS if "windows" not in item}}))
""".format(
py_repository = rctx.attr.user_repository_name,
host_platform = host_platform,
@@ -181,7 +187,15 @@ alias(name = "pip", actual = select({{":" + item: "@{py_repository}_
rctx.file("defs.bzl", content = """\
# Generated by python/private/toolchains_repo.bzl
-load("{rules_python}//python/config_settings:transition.bzl", _py_binary = "py_binary", _py_test = "py_test")
+load(
+ "{rules_python}//python/config_settings:transition.bzl",
+ _py_binary = "py_binary",
+ _py_test = "py_test",
+)
+load(
+ "{rules_python}//python/entry_points:py_console_script_binary.bzl",
+ _py_console_script_binary = "py_console_script_binary",
+)
load("{rules_python}//python:pip.bzl", _compile_pip_requirements = "compile_pip_requirements")
host_platform = "{host_platform}"
@@ -194,6 +208,13 @@ def py_binary(name, **kwargs):
**kwargs
)
+def py_console_script_binary(name, **kwargs):
+ return _py_console_script_binary(
+ name = name,
+ binary_rule = py_binary,
+ **kwargs
+ )
+
def py_test(name, **kwargs):
return _py_test(
name = name,
@@ -223,6 +244,9 @@ toolchain_aliases = repository_rule(
a BUILD.bazel file declaring aliases to the host platform's targets.
""",
attrs = {
+ "platforms": attr.string_list(
+ doc = "List of platforms for which aliases shall be created",
+ ),
"python_version": attr.string(doc = "The Python version."),
"user_repository_name": attr.string(
mandatory = True,
@@ -246,6 +270,7 @@ load(
_host_platform = "host_platform",
_interpreter = "interpreter",
_py_binary = "py_binary",
+ _py_console_script_binary = "py_console_script_binary",
_py_test = "py_test",
)
@@ -253,6 +278,7 @@ compile_pip_requirements = _compile_pip_requirements
host_platform = _host_platform
interpreter = _interpreter
py_binary = _py_binary
+py_console_script_binary = _py_console_script_binary
py_test = _py_test
""".format(
repository_name = repository_name,
@@ -325,7 +351,7 @@ def get_host_os_arch(rctx):
os_name = WINDOWS_NAME
else:
# This is not ideal, but bazel doesn't directly expose arch.
- arch = rctx.execute(["uname", "-m"]).stdout.strip()
+ arch = rctx.execute([which_with_fail("uname", rctx), "-m"]).stdout.strip()
# Normalize the os_name.
if "mac" in os_name.lower():
diff --git a/python/private/util.bzl b/python/private/util.bzl
index 6c8761d..71476f9 100644
--- a/python/private/util.bzl
+++ b/python/private/util.bzl
@@ -83,3 +83,9 @@ def add_tag(attrs, tag):
attrs["tags"] = tags + [tag]
else:
attrs["tags"] = [tag]
+
+IS_BAZEL_7_OR_HIGHER = hasattr(native, "starlark_doc_extract")
+
+# Bazel 5.4 has a bug where every access of testing.ExecutionInfo is a
+# different object that isn't equal to any other. This is fixed in bazel 6+.
+IS_BAZEL_6_OR_HIGHER = testing.ExecutionInfo == testing.ExecutionInfo
diff --git a/python/private/which.bzl b/python/private/which.bzl
new file mode 100644
index 0000000..b0cbddb
--- /dev/null
+++ b/python/private/which.bzl
@@ -0,0 +1,32 @@
+# 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.
+
+"""Wrapper for repository which call"""
+
+_binary_not_found_msg = "Unable to find the binary '{binary_name}'. Please update your PATH to include '{binary_name}'."
+
+def which_with_fail(binary_name, rctx):
+ """Tests to see if a binary exists, and otherwise fails with a message.
+
+ Args:
+ binary_name: name of the binary to find.
+ rctx: repository context.
+
+ Returns:
+ rctx.Path for the binary.
+ """
+ binary = rctx.which(binary_name)
+ if binary == None:
+ fail(_binary_not_found_msg.format(binary_name = binary_name))
+ return binary
diff --git a/python/private/whl_target_platforms.bzl b/python/private/whl_target_platforms.bzl
new file mode 100644
index 0000000..2c63efe
--- /dev/null
+++ b/python/private/whl_target_platforms.bzl
@@ -0,0 +1,80 @@
+# 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.
+
+"""
+A starlark implementation of the wheel platform tag parsing to get the target platform.
+"""
+
+# The order of the dictionaries is to keep definitions with their aliases next to each
+# other
+_CPU_ALIASES = {
+ "x86_32": "x86_32",
+ "i386": "x86_32",
+ "i686": "x86_32",
+ "x86": "x86_32",
+ "x86_64": "x86_64",
+ "amd64": "x86_64",
+ "aarch64": "aarch64",
+ "arm64": "aarch64",
+ "ppc": "ppc",
+ "ppc64le": "ppc",
+ "s390x": "s390x",
+} # buildifier: disable=unsorted-dict-items
+
+_OS_PREFIXES = {
+ "linux": "linux",
+ "manylinux": "linux",
+ "musllinux": "linux",
+ "macos": "osx",
+ "win": "windows",
+} # buildifier: disable=unsorted-dict-items
+
+def whl_target_platforms(tag):
+ """Parse the wheel platform tag and return (os, cpu) tuples.
+
+ Args:
+ tag (str): The platform_tag part of the wheel name. See
+ ./parse_whl_name.bzl for more details.
+
+ Returns:
+ A list of structs, with attributes:
+ * os: str, one of the _OS_PREFIXES values
+ * cpu: str, one of the _CPU_PREFIXES values
+ """
+ cpus = _cpu_from_tag(tag)
+
+ for prefix, os in _OS_PREFIXES.items():
+ if tag.startswith(prefix):
+ return [
+ struct(os = os, cpu = cpu)
+ for cpu in cpus
+ ]
+
+ fail("unknown tag os: {}".format(tag))
+
+def _cpu_from_tag(tag):
+ candidate = [
+ cpu
+ for input, cpu in _CPU_ALIASES.items()
+ if tag.endswith(input)
+ ]
+ if candidate:
+ return candidate
+
+ if tag == "win32":
+ return ["x86_32"]
+ elif tag.endswith("universal2") and tag.startswith("macosx"):
+ return ["x86_64", "aarch64"]
+ else:
+ fail("Unrecognized tag: '{}': cannot determine CPU".format(tag))
diff --git a/python/proto/BUILD.bazel b/python/proto/BUILD.bazel
new file mode 100644
index 0000000..9f60574
--- /dev/null
+++ b/python/proto/BUILD.bazel
@@ -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.
+
+package(default_visibility = ["//visibility:public"])
+
+# Toolchain type provided by proto_lang_toolchain rule and used by py_proto_library
+toolchain_type(name = "toolchain_type")
diff --git a/python/py_binary.bzl b/python/py_binary.bzl
index 6b6f7e0..ed63ebe 100644
--- a/python/py_binary.bzl
+++ b/python/py_binary.bzl
@@ -14,7 +14,13 @@
"""Public entry point for py_binary."""
+load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("//python/private:register_extension_info.bzl", "register_extension_info")
load("//python/private:util.bzl", "add_migration_tag")
+load("//python/private/common:py_binary_macro_bazel.bzl", _starlark_py_binary = "py_binary")
+
+# buildifier: disable=native-python
+_py_binary_impl = _starlark_py_binary if config.enable_pystar else native.py_binary
def py_binary(**attrs):
"""See the Bazel core [py_binary](https://docs.bazel.build/versions/master/be/python.html#py_binary) documentation.
@@ -27,5 +33,9 @@ def py_binary(**attrs):
if attrs.get("srcs_version") in ("PY2", "PY2ONLY"):
fail("Python 2 is no longer supported: https://github.com/bazelbuild/rules_python/issues/886")
- # buildifier: disable=native-python
- native.py_binary(**add_migration_tag(attrs))
+ _py_binary_impl(**add_migration_tag(attrs))
+
+register_extension_info(
+ extension = py_binary,
+ label_regex_for_dep = "{extension_name}",
+)
diff --git a/python/py_cc_link_params_info.bzl b/python/py_cc_link_params_info.bzl
index 0ebd64b..42d8daf 100644
--- a/python/py_cc_link_params_info.bzl
+++ b/python/py_cc_link_params_info.bzl
@@ -1,3 +1,6 @@
"""Public entry point for PyCcLinkParamsInfo."""
-PyCcLinkParamsInfo = PyCcLinkParamsProvider
+load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("//python/private/common:providers.bzl", _starlark_PyCcLinkParamsProvider = "PyCcLinkParamsProvider")
+
+PyCcLinkParamsInfo = _starlark_PyCcLinkParamsProvider if config.enable_pystar else PyCcLinkParamsProvider
diff --git a/python/py_info.bzl b/python/py_info.bzl
index 2c3997d..0af35ac 100644
--- a/python/py_info.bzl
+++ b/python/py_info.bzl
@@ -14,6 +14,8 @@
"""Public entry point for PyInfo."""
-load("//python/private:reexports.bzl", "internal_PyInfo")
+load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("//python/private:reexports.bzl", "BuiltinPyInfo")
+load("//python/private/common:providers.bzl", _starlark_PyInfo = "PyInfo")
-PyInfo = internal_PyInfo
+PyInfo = _starlark_PyInfo if config.enable_pystar else BuiltinPyInfo
diff --git a/python/py_library.bzl b/python/py_library.bzl
index d54cbb2..2aa797a 100644
--- a/python/py_library.bzl
+++ b/python/py_library.bzl
@@ -14,7 +14,13 @@
"""Public entry point for py_library."""
+load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("//python/private:register_extension_info.bzl", "register_extension_info")
load("//python/private:util.bzl", "add_migration_tag")
+load("//python/private/common:py_library_macro_bazel.bzl", _starlark_py_library = "py_library")
+
+# buildifier: disable=native-python
+_py_library_impl = _starlark_py_library if config.enable_pystar else native.py_library
def py_library(**attrs):
"""See the Bazel core [py_library](https://docs.bazel.build/versions/master/be/python.html#py_library) documentation.
@@ -25,5 +31,9 @@ def py_library(**attrs):
if attrs.get("srcs_version") in ("PY2", "PY2ONLY"):
fail("Python 2 is no longer supported: https://github.com/bazelbuild/rules_python/issues/886")
- # buildifier: disable=native-python
- native.py_library(**add_migration_tag(attrs))
+ _py_library_impl(**add_migration_tag(attrs))
+
+register_extension_info(
+ extension = py_library,
+ label_regex_for_dep = "{extension_name}",
+)
diff --git a/python/py_runtime.bzl b/python/py_runtime.bzl
index b70f9d4..d4b913d 100644
--- a/python/py_runtime.bzl
+++ b/python/py_runtime.bzl
@@ -14,7 +14,11 @@
"""Public entry point for py_runtime."""
-load("//python/private:util.bzl", "add_migration_tag")
+load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER", "add_migration_tag")
+load("//python/private/common:py_runtime_macro.bzl", _starlark_py_runtime = "py_runtime")
+
+# buildifier: disable=native-python
+_py_runtime_impl = _starlark_py_runtime if IS_BAZEL_6_OR_HIGHER else native.py_runtime
def py_runtime(**attrs):
"""See the Bazel core [py_runtime](https://docs.bazel.build/versions/master/be/python.html#py_runtime) documentation.
@@ -25,5 +29,4 @@ def py_runtime(**attrs):
if attrs.get("python_version") == "PY2":
fail("Python 2 is no longer supported: see https://github.com/bazelbuild/rules_python/issues/886")
- # buildifier: disable=native-python
- native.py_runtime(**add_migration_tag(attrs))
+ _py_runtime_impl(**add_migration_tag(attrs))
diff --git a/python/py_runtime_info.bzl b/python/py_runtime_info.bzl
index 15598ee..c0a9288 100644
--- a/python/py_runtime_info.bzl
+++ b/python/py_runtime_info.bzl
@@ -14,6 +14,8 @@
"""Public entry point for PyRuntimeInfo."""
-load("//python/private:reexports.bzl", "internal_PyRuntimeInfo")
+load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
+load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER")
+load("//python/private/common:providers.bzl", _starlark_PyRuntimeInfo = "PyRuntimeInfo")
-PyRuntimeInfo = internal_PyRuntimeInfo
+PyRuntimeInfo = _starlark_PyRuntimeInfo if IS_BAZEL_6_OR_HIGHER else BuiltinPyRuntimeInfo
diff --git a/python/py_runtime_pair.bzl b/python/py_runtime_pair.bzl
index 951c606..1728dcd 100644
--- a/python/py_runtime_pair.bzl
+++ b/python/py_runtime_pair.bzl
@@ -14,7 +14,11 @@
"""Public entry point for py_runtime_pair."""
-load("@bazel_tools//tools/python:toolchain.bzl", _py_runtime_pair = "py_runtime_pair")
+load("@bazel_tools//tools/python:toolchain.bzl", _bazel_tools_impl = "py_runtime_pair")
+load("//python/private:py_runtime_pair_macro.bzl", _starlark_impl = "py_runtime_pair")
+load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER")
+
+_py_runtime_pair = _starlark_impl if IS_BAZEL_6_OR_HIGHER else _bazel_tools_impl
# NOTE: This doc is copy/pasted from the builtin py_runtime_pair rule so our
# doc generator gives useful API docs.
@@ -43,7 +47,8 @@ def py_runtime_pair(name, py2_runtime = None, py3_runtime = None, **attrs):
```python
# In your BUILD file...
- load("@rules_python//python:defs.bzl", "py_runtime_pair")
+ load("@rules_python//python:py_runtime.bzl", "py_runtime")
+ load("@rules_python//python:py_runtime_pair.bzl", "py_runtime_pair")
py_runtime(
name = "my_py3_runtime",
diff --git a/python/py_test.bzl b/python/py_test.bzl
index 09580c0..f58f067 100644
--- a/python/py_test.bzl
+++ b/python/py_test.bzl
@@ -14,7 +14,13 @@
"""Public entry point for py_test."""
+load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("//python/private:register_extension_info.bzl", "register_extension_info")
load("//python/private:util.bzl", "add_migration_tag")
+load("//python/private/common:py_test_macro_bazel.bzl", _starlark_py_test = "py_test")
+
+# buildifier: disable=native-python
+_py_test_impl = _starlark_py_test if config.enable_pystar else native.py_test
def py_test(**attrs):
"""See the Bazel core [py_test](https://docs.bazel.build/versions/master/be/python.html#py_test) documentation.
@@ -28,4 +34,9 @@ def py_test(**attrs):
fail("Python 2 is no longer supported: https://github.com/bazelbuild/rules_python/issues/886")
# buildifier: disable=native-python
- native.py_test(**add_migration_tag(attrs))
+ _py_test_impl(**add_migration_tag(attrs))
+
+register_extension_info(
+ extension = py_test,
+ label_regex_for_dep = "{extension_name}",
+)
diff --git a/python/repositories.bzl b/python/repositories.bzl
index 62d9421..21becb5 100644
--- a/python/repositories.bzl
+++ b/python/repositories.bzl
@@ -19,18 +19,22 @@ For historic reasons, pip_repositories() is defined in //python:pip.bzl.
load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
+load("//python/private:auth.bzl", "get_auth")
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
load("//python/private:coverage_deps.bzl", "coverage_dep")
+load("//python/private:full_version.bzl", "full_version")
+load("//python/private:internal_config_repo.bzl", "internal_config_repo")
load(
"//python/private:toolchains_repo.bzl",
"multi_toolchain_aliases",
"toolchain_aliases",
"toolchains_repo",
)
+load("//python/private:which.bzl", "which_with_fail")
load(
":versions.bzl",
"DEFAULT_RELEASE_BASE_URL",
- "MINOR_MAPPING",
"PLATFORMS",
"TOOL_VERSIONS",
"get_release_info",
@@ -45,6 +49,10 @@ def py_repositories():
This function should be loaded and called in the user's WORKSPACE.
With bzlmod enabled, this function is not needed since MODULE.bazel handles transitive deps.
"""
+ maybe(
+ internal_config_repo,
+ name = "rules_python_internal",
+ )
http_archive(
name = "bazel_skylib",
sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506",
@@ -53,6 +61,7 @@ def py_repositories():
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
],
)
+ pip_install_dependencies()
########
# Remaining content of the file is only used to support toolchains.
@@ -60,39 +69,26 @@ def py_repositories():
STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER"
-def get_interpreter_dirname(rctx, python_interpreter_target):
- """Get a python interpreter target dirname.
-
- Args:
- rctx (repository_ctx): The repository rule's context object.
- python_interpreter_target (Target): A target representing a python interpreter.
-
- Returns:
- str: The Python interpreter directory.
- """
-
- return rctx.path(Label("{}//:WORKSPACE".format(str(python_interpreter_target).split("//")[0]))).dirname
-
-def is_standalone_interpreter(rctx, python_interpreter_target):
+def is_standalone_interpreter(rctx, python_interpreter_path):
"""Query a python interpreter target for whether or not it's a rules_rust provided toolchain
Args:
rctx (repository_ctx): The repository rule's context object.
- python_interpreter_target (Target): A target representing a python interpreter.
+ python_interpreter_path (path): A path representing the interpreter.
Returns:
bool: Whether or not the target is from a rules_python generated toolchain.
"""
# Only update the location when using a hermetic toolchain.
- if not python_interpreter_target:
+ if not python_interpreter_path:
return False
# This is a rules_python provided toolchain.
return rctx.execute([
"ls",
"{}/{}".format(
- get_interpreter_dirname(rctx, python_interpreter_target),
+ python_interpreter_path.dirname,
STANDALONE_INTERPRETER_FILENAME,
),
]).return_code == 0
@@ -108,12 +104,14 @@ def _python_repository_impl(rctx):
python_short_version = python_version.rpartition(".")[0]
release_filename = rctx.attr.release_filename
urls = rctx.attr.urls or [rctx.attr.url]
+ auth = get_auth(rctx, urls)
if release_filename.endswith(".zst"):
rctx.download(
url = urls,
sha256 = rctx.attr.sha256,
output = release_filename,
+ auth = auth,
)
unzstd = rctx.which("unzstd")
if not unzstd:
@@ -121,10 +119,12 @@ def _python_repository_impl(rctx):
rctx.download_and_extract(
url = url,
sha256 = rctx.attr.zstd_sha256,
+ auth = auth,
)
working_directory = "zstd-{version}".format(version = rctx.attr.zstd_version)
+
make_result = rctx.execute(
- ["make", "--jobs=4"],
+ [which_with_fail("make", rctx), "--jobs=4"],
timeout = 600,
quiet = True,
working_directory = working_directory,
@@ -140,7 +140,7 @@ def _python_repository_impl(rctx):
rctx.symlink(zstd, unzstd)
exec_result = rctx.execute([
- "tar",
+ which_with_fail("tar", rctx),
"--extract",
"--strip-components=2",
"--use-compress-program={unzstd}".format(unzstd = unzstd),
@@ -157,6 +157,7 @@ def _python_repository_impl(rctx):
url = urls,
sha256 = rctx.attr.sha256,
stripPrefix = rctx.attr.strip_prefix,
+ auth = auth,
)
patches = rctx.attr.patches
@@ -179,15 +180,16 @@ def _python_repository_impl(rctx):
if not rctx.attr.ignore_root_user_error:
if "windows" not in rctx.os.name:
lib_dir = "lib" if "windows" not in platform else "Lib"
- exec_result = rctx.execute(["chmod", "-R", "ugo-w", lib_dir])
+
+ exec_result = rctx.execute([which_with_fail("chmod", rctx), "-R", "ugo-w", lib_dir])
if exec_result.return_code != 0:
fail_msg = "Failed to make interpreter installation read-only. 'chmod' error msg: {}".format(
exec_result.stderr,
)
fail(fail_msg)
- exec_result = rctx.execute(["touch", "{}/.test".format(lib_dir)])
+ exec_result = rctx.execute([which_with_fail("touch", rctx), "{}/.test".format(lib_dir)])
if exec_result.return_code == 0:
- exec_result = rctx.execute(["id", "-u"])
+ exec_result = rctx.execute([which_with_fail("id", rctx), "-u"])
if exec_result.return_code != 0:
fail("Could not determine current user ID. 'id -u' error msg: {}".format(
exec_result.stderr,
@@ -211,6 +213,7 @@ def _python_repository_impl(rctx):
# tests for the standard libraries.
"lib/python{python_version}/**/test/**".format(python_version = python_short_version),
"lib/python{python_version}/**/tests/**".format(python_version = python_short_version),
+ "**/__pycache__/*.pyc.*", # During pyc creation, temp files named *.pyc.NNN are created
]
if rctx.attr.ignore_root_user_error:
@@ -220,7 +223,6 @@ def _python_repository_impl(rctx):
# the definition of this filegroup will change, and depending rules will get invalidated."
# See https://github.com/bazelbuild/rules_python/issues/1008 for unconditionally adding these to toolchains so we can stop ignoring them."
"**/__pycache__/*.pyc",
- "**/__pycache__/*.pyc.*", # During pyc creation, temp files named *.pyc.NNN are created
"**/__pycache__/*.pyo",
]
@@ -236,6 +238,7 @@ def _python_repository_impl(rctx):
"libs/**",
"Scripts/**",
"share/**",
+ "tcl/**",
]
else:
glob_include += [
@@ -265,7 +268,8 @@ def _python_repository_impl(rctx):
build_content = """\
# Generated by python/repositories.bzl
-load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
+load("@rules_python//python:py_runtime.bzl", "py_runtime")
+load("@rules_python//python:py_runtime_pair.bzl", "py_runtime_pair")
load("@rules_python//python/cc:py_cc_toolchain.bzl", "py_cc_toolchain")
package(default_visibility = ["//visibility:public"])
@@ -358,11 +362,13 @@ py_cc_toolchain(
rctx.file("BUILD.bazel", build_content)
attrs = {
+ "auth_patterns": rctx.attr.auth_patterns,
"coverage_tool": rctx.attr.coverage_tool,
"distutils": rctx.attr.distutils,
"distutils_content": rctx.attr.distutils_content,
"ignore_root_user_error": rctx.attr.ignore_root_user_error,
"name": rctx.attr.name,
+ "netrc": rctx.attr.netrc,
"patches": rctx.attr.patches,
"platform": platform,
"python_version": python_version,
@@ -382,6 +388,9 @@ python_repository = repository_rule(
_python_repository_impl,
doc = "Fetches the external tools needed for the Python toolchain.",
attrs = {
+ "auth_patterns": attr.string_dict(
+ doc = "Override mapping of hostnames to authorization patterns; mirrors the eponymous attribute from http_archive",
+ ),
"coverage_tool": attr.string(
# Mirrors the definition at
# https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/python/py_runtime_rule.bzl
@@ -422,6 +431,9 @@ For more information see the official bazel docs
doc = "Whether the check for root should be ignored or not. This causes cache misses with .pyc files.",
mandatory = False,
),
+ "netrc": attr.string(
+ doc = ".netrc file to use for authentication; mirrors the eponymous attribute from http_archive",
+ ),
"patches": attr.label_list(
doc = "A list of patch files to apply to the unpacked interpreter",
mandatory = False,
@@ -505,8 +517,7 @@ def python_register_toolchains(
base_url = kwargs.pop("base_url", DEFAULT_RELEASE_BASE_URL)
- if python_version in MINOR_MAPPING:
- python_version = MINOR_MAPPING[python_version]
+ python_version = full_version(python_version)
toolchain_repo_name = "{name}_toolchains".format(name = name)
@@ -525,11 +536,13 @@ def python_register_toolchains(
))
register_coverage_tool = False
+ loaded_platforms = []
for platform in PLATFORMS.keys():
sha256 = tool_versions[python_version]["sha256"].get(platform, None)
if not sha256:
continue
+ loaded_platforms.append(platform)
(release_filename, urls, strip_prefix, patches) = get_release_info(platform, python_version, base_url, tool_versions)
# allow passing in a tool version
@@ -571,11 +584,16 @@ def python_register_toolchains(
toolchain_repo_name = toolchain_repo_name,
platform = platform,
))
+ native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_cc_toolchain".format(
+ toolchain_repo_name = toolchain_repo_name,
+ platform = platform,
+ ))
toolchain_aliases(
name = name,
python_version = python_version,
user_repository_name = name,
+ platforms = loaded_platforms,
)
# in bzlmod we write out our own toolchain repos
diff --git a/python/runfiles/BUILD.bazel b/python/runfiles/BUILD.bazel
index c6cfc2f..55c25c8 100644
--- a/python/runfiles/BUILD.bazel
+++ b/python/runfiles/BUILD.bazel
@@ -27,6 +27,7 @@ py_library(
"__init__.py",
"runfiles.py",
],
+ data = ["py.typed"],
imports = [
# Add the repo root so `import python.runfiles.runfiles` works. This makes it agnostic
# to the --experimental_python_import_all_repositories setting.
@@ -49,6 +50,7 @@ py_wheel(
dist_folder = "dist",
distribution = "bazel_runfiles",
homepage = "https://github.com/bazelbuild/rules_python",
+ python_requires = ">=3.7",
strip_path_prefixes = ["python"],
twine = "@publish_deps_twine//:pkg",
# this can be replaced by building with --stamp --embed_label=1.2.3
diff --git a/python/runfiles/py.typed b/python/runfiles/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/runfiles/py.typed
diff --git a/python/runfiles/runfiles.py b/python/runfiles/runfiles.py
index 9bdb61b..2240979 100644
--- a/python/runfiles/runfiles.py
+++ b/python/runfiles/runfiles.py
@@ -14,82 +14,116 @@
"""Runfiles lookup library for Bazel-built Python binaries and tests.
-See README.md for usage instructions.
+See @rules_python//python/runfiles/README.rst for usage instructions.
"""
import inspect
import os
import posixpath
import sys
+from typing import Dict, Optional, Tuple, Union
-if False:
- # Mypy needs these symbols imported, but since they only exist in python 3.5+,
- # this import may fail at runtime. Luckily mypy can follow this conditional import.
- from typing import Callable, Dict, Optional, Tuple, Union
-
-
-def CreateManifestBased(manifest_path):
- # type: (str) -> _Runfiles
- return _Runfiles(_ManifestBased(manifest_path))
+class _ManifestBased:
+ """`Runfiles` strategy that parses a runfiles-manifest to look up runfiles."""
-def CreateDirectoryBased(runfiles_dir_path):
- # type: (str) -> _Runfiles
- return _Runfiles(_DirectoryBased(runfiles_dir_path))
+ def __init__(self, path: str) -> None:
+ if not path:
+ raise ValueError()
+ if not isinstance(path, str):
+ raise TypeError()
+ self._path = path
+ self._runfiles = _ManifestBased._LoadRunfiles(path)
+ def RlocationChecked(self, path: str) -> Optional[str]:
+ """Returns the runtime path of a runfile."""
+ exact_match = self._runfiles.get(path)
+ if exact_match:
+ return exact_match
+ # If path references a runfile that lies under a directory that
+ # itself is a runfile, then only the directory is listed in the
+ # manifest. Look up all prefixes of path in the manifest and append
+ # the relative path from the prefix to the looked up path.
+ prefix_end = len(path)
+ while True:
+ prefix_end = path.rfind("/", 0, prefix_end - 1)
+ if prefix_end == -1:
+ return None
+ prefix_match = self._runfiles.get(path[0:prefix_end])
+ if prefix_match:
+ return prefix_match + "/" + path[prefix_end + 1 :]
-def Create(env=None):
- # type: (Optional[Dict[str, str]]) -> Optional[_Runfiles]
- """Returns a new `Runfiles` instance.
+ @staticmethod
+ def _LoadRunfiles(path: str) -> Dict[str, str]:
+ """Loads the runfiles manifest."""
+ result = {}
+ with open(path, "r") as f:
+ for line in f:
+ line = line.strip()
+ if line:
+ tokens = line.split(" ", 1)
+ if len(tokens) == 1:
+ result[line] = line
+ else:
+ result[tokens[0]] = tokens[1]
+ return result
- The returned object is either:
- - manifest-based, meaning it looks up runfile paths from a manifest file, or
- - directory-based, meaning it looks up runfile paths under a given directory
- path
+ def _GetRunfilesDir(self) -> str:
+ if self._path.endswith("/MANIFEST") or self._path.endswith("\\MANIFEST"):
+ return self._path[: -len("/MANIFEST")]
+ if self._path.endswith(".runfiles_manifest"):
+ return self._path[: -len("_manifest")]
+ return ""
- If `env` contains "RUNFILES_MANIFEST_FILE" with non-empty value, this method
- returns a manifest-based implementation. The object eagerly reads and caches
- the whole manifest file upon instantiation; this may be relevant for
- performance consideration.
+ def EnvVars(self) -> Dict[str, str]:
+ directory = self._GetRunfilesDir()
+ return {
+ "RUNFILES_MANIFEST_FILE": self._path,
+ "RUNFILES_DIR": directory,
+ # TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
+ # pick up RUNFILES_DIR.
+ "JAVA_RUNFILES": directory,
+ }
- Otherwise, if `env` contains "RUNFILES_DIR" with non-empty value (checked in
- this priority order), this method returns a directory-based implementation.
- If neither cases apply, this method returns null.
+class _DirectoryBased:
+ """`Runfiles` strategy that appends runfiles paths to the runfiles root."""
- Args:
- env: {string: string}; optional; the map of environment variables. If None,
- this function uses the environment variable map of this process.
- Raises:
- IOError: if some IO error occurs.
- """
- env_map = os.environ if env is None else env
- manifest = env_map.get("RUNFILES_MANIFEST_FILE")
- if manifest:
- return CreateManifestBased(manifest)
+ def __init__(self, path: str) -> None:
+ if not path:
+ raise ValueError()
+ if not isinstance(path, str):
+ raise TypeError()
+ self._runfiles_root = path
- directory = env_map.get("RUNFILES_DIR")
- if directory:
- return CreateDirectoryBased(directory)
+ def RlocationChecked(self, path: str) -> str:
+ # Use posixpath instead of os.path, because Bazel only creates a runfiles
+ # tree on Unix platforms, so `Create()` will only create a directory-based
+ # runfiles strategy on those platforms.
+ return posixpath.join(self._runfiles_root, path)
- return None
+ def EnvVars(self) -> Dict[str, str]:
+ return {
+ "RUNFILES_DIR": self._runfiles_root,
+ # TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
+ # pick up RUNFILES_DIR.
+ "JAVA_RUNFILES": self._runfiles_root,
+ }
-class _Runfiles(object):
+class Runfiles:
"""Returns the runtime location of runfiles.
Runfiles are data-dependencies of Bazel-built binaries and tests.
"""
- def __init__(self, strategy):
- # type: (Union[_ManifestBased, _DirectoryBased]) -> None
+ def __init__(self, strategy: Union[_ManifestBased, _DirectoryBased]) -> None:
self._strategy = strategy
self._python_runfiles_root = _FindPythonRunfilesRoot()
self._repo_mapping = _ParseRepoMapping(
strategy.RlocationChecked("_repo_mapping")
)
- def Rlocation(self, path, source_repo=None):
- # type: (str, Optional[str]) -> Optional[str]
+ def Rlocation(self, path: str, source_repo: Optional[str] = None) -> Optional[str]:
"""Returns the runtime path of a runfile.
Runfiles are data-dependencies of Bazel-built binaries and tests.
@@ -153,14 +187,17 @@ class _Runfiles(object):
# which also should not be mapped.
return self._strategy.RlocationChecked(path)
+ assert (
+ source_repo is not None
+ ), "BUG: if the `source_repo` is None, we should never go past the `if` statement above"
+
# target_repo is an apparent repository name. Look up the corresponding
# canonical repository name with respect to the current repository,
# identified by its canonical name.
target_canonical = self._repo_mapping[(source_repo, target_repo)]
return self._strategy.RlocationChecked(target_canonical + "/" + remainder)
- def EnvVars(self):
- # type: () -> Dict[str, str]
+ def EnvVars(self) -> Dict[str, str]:
"""Returns environment variables for subprocesses.
The caller should set the returned key-value pairs in the environment of
@@ -173,8 +210,7 @@ class _Runfiles(object):
"""
return self._strategy.EnvVars()
- def CurrentRepository(self, frame=1):
- # type: (int) -> str
+ def CurrentRepository(self, frame: int = 1) -> str:
"""Returns the canonical name of the caller's Bazel repository.
For example, this function returns '' (the empty string) when called
@@ -204,12 +240,11 @@ class _Runfiles(object):
ValueError: if the caller cannot be determined or the caller's file
path is not contained in the Python runfiles tree
"""
- # pylint:disable=protected-access # for sys._getframe
- # pylint:disable=raise-missing-from # we're still supporting Python 2
try:
+ # pylint: disable-next=protected-access
caller_path = inspect.getfile(sys._getframe(frame))
- except (TypeError, ValueError):
- raise ValueError("failed to determine caller's file path")
+ except (TypeError, ValueError) as exc:
+ raise ValueError("failed to determine caller's file path") from exc
caller_runfiles_path = os.path.relpath(caller_path, self._python_runfiles_root)
if caller_runfiles_path.startswith(".." + os.path.sep):
raise ValueError(
@@ -233,8 +268,11 @@ class _Runfiles(object):
return caller_runfiles_directory
-def _FindPythonRunfilesRoot():
- # type: () -> str
+# Support legacy imports by defining a private symbol.
+_Runfiles = Runfiles
+
+
+def _FindPythonRunfilesRoot() -> str:
"""Finds the root of the Python runfiles tree."""
root = __file__
# Walk up our own runfiles path to the root of the runfiles tree from which
@@ -246,8 +284,7 @@ def _FindPythonRunfilesRoot():
return root
-def _ParseRepoMapping(repo_mapping_path):
- # type: (Optional[str]) -> Dict[Tuple[str, str], str]
+def _ParseRepoMapping(repo_mapping_path: Optional[str]) -> Dict[Tuple[str, str], str]:
"""Parses the repository mapping manifest."""
# If the repository mapping file can't be found, that is not an error: We
# might be running without Bzlmod enabled or there may not be any runfiles.
@@ -271,98 +308,45 @@ def _ParseRepoMapping(repo_mapping_path):
return repo_mapping
-class _ManifestBased(object):
- """`Runfiles` strategy that parses a runfiles-manifest to look up runfiles."""
+def CreateManifestBased(manifest_path: str) -> Runfiles:
+ return Runfiles(_ManifestBased(manifest_path))
- def __init__(self, path):
- # type: (str) -> None
- if not path:
- raise ValueError()
- if not isinstance(path, str):
- raise TypeError()
- self._path = path
- self._runfiles = _ManifestBased._LoadRunfiles(path)
- def RlocationChecked(self, path):
- # type: (str) -> Optional[str]
- """Returns the runtime path of a runfile."""
- exact_match = self._runfiles.get(path)
- if exact_match:
- return exact_match
- # If path references a runfile that lies under a directory that
- # itself is a runfile, then only the directory is listed in the
- # manifest. Look up all prefixes of path in the manifest and append
- # the relative path from the prefix to the looked up path.
- prefix_end = len(path)
- while True:
- prefix_end = path.rfind("/", 0, prefix_end - 1)
- if prefix_end == -1:
- return None
- prefix_match = self._runfiles.get(path[0:prefix_end])
- if prefix_match:
- return prefix_match + "/" + path[prefix_end + 1 :]
+def CreateDirectoryBased(runfiles_dir_path: str) -> Runfiles:
+ return Runfiles(_DirectoryBased(runfiles_dir_path))
- @staticmethod
- def _LoadRunfiles(path):
- # type: (str) -> Dict[str, str]
- """Loads the runfiles manifest."""
- result = {}
- with open(path, "r") as f:
- for line in f:
- line = line.strip()
- if line:
- tokens = line.split(" ", 1)
- if len(tokens) == 1:
- result[line] = line
- else:
- result[tokens[0]] = tokens[1]
- return result
- def _GetRunfilesDir(self):
- # type: () -> str
- if self._path.endswith("/MANIFEST") or self._path.endswith("\\MANIFEST"):
- return self._path[: -len("/MANIFEST")]
- elif self._path.endswith(".runfiles_manifest"):
- return self._path[: -len("_manifest")]
- else:
- return ""
+def Create(env: Optional[Dict[str, str]] = None) -> Optional[Runfiles]:
+ """Returns a new `Runfiles` instance.
- def EnvVars(self):
- # type: () -> Dict[str, str]
- directory = self._GetRunfilesDir()
- return {
- "RUNFILES_MANIFEST_FILE": self._path,
- "RUNFILES_DIR": directory,
- # TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
- # pick up RUNFILES_DIR.
- "JAVA_RUNFILES": directory,
- }
+ The returned object is either:
+ - manifest-based, meaning it looks up runfile paths from a manifest file, or
+ - directory-based, meaning it looks up runfile paths under a given directory
+ path
+ If `env` contains "RUNFILES_MANIFEST_FILE" with non-empty value, this method
+ returns a manifest-based implementation. The object eagerly reads and caches
+ the whole manifest file upon instantiation; this may be relevant for
+ performance consideration.
-class _DirectoryBased(object):
- """`Runfiles` strategy that appends runfiles paths to the runfiles root."""
+ Otherwise, if `env` contains "RUNFILES_DIR" with non-empty value (checked in
+ this priority order), this method returns a directory-based implementation.
- def __init__(self, path):
- # type: (str) -> None
- if not path:
- raise ValueError()
- if not isinstance(path, str):
- raise TypeError()
- self._runfiles_root = path
+ If neither cases apply, this method returns null.
- def RlocationChecked(self, path):
- # type: (str) -> str
+ Args:
+ env: {string: string}; optional; the map of environment variables. If None,
+ this function uses the environment variable map of this process.
+ Raises:
+ IOError: if some IO error occurs.
+ """
+ env_map = os.environ if env is None else env
+ manifest = env_map.get("RUNFILES_MANIFEST_FILE")
+ if manifest:
+ return CreateManifestBased(manifest)
- # Use posixpath instead of os.path, because Bazel only creates a runfiles
- # tree on Unix platforms, so `Create()` will only create a directory-based
- # runfiles strategy on those platforms.
- return posixpath.join(self._runfiles_root, path)
+ directory = env_map.get("RUNFILES_DIR")
+ if directory:
+ return CreateDirectoryBased(directory)
- def EnvVars(self):
- # type: () -> Dict[str, str]
- return {
- "RUNFILES_DIR": self._runfiles_root,
- # TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
- # pick up RUNFILES_DIR.
- "JAVA_RUNFILES": self._runfiles_root,
- }
+ return None
diff --git a/python/versions.bzl b/python/versions.bzl
index a88c982..6c9bf25 100644
--- a/python/versions.bzl
+++ b/python/versions.bzl
@@ -97,6 +97,28 @@ TOOL_VERSIONS = {
},
"strip_prefix": "python",
},
+ "3.8.17": {
+ "url": "20230826/cpython-{python_version}+20230826-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "c6f7a130d0044a78e39648f4dae56dcff5a41eba91888a99f6e560507162e6a1",
+ "aarch64-unknown-linux-gnu": "9f6d585091fe26906ff1dbb80437a3fe37a1e3db34d6ecc0098f3d6a78356682",
+ "x86_64-apple-darwin": "155b06821607bae1a58ecc60a7d036b358c766f19e493b8876190765c883a5c2",
+ "x86_64-pc-windows-msvc": "6428e1b4e0b4482d390828de7d4c82815257443416cb786abe10cb2466ca68cd",
+ "x86_64-unknown-linux-gnu": "8d3e1826c0bb7821ec63288038644808a2d45553245af106c685ef5892fabcd8",
+ },
+ "strip_prefix": "python",
+ },
+ "3.8.18": {
+ "url": "20231002/cpython-{python_version}+20231002-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "1825b1f7220bc93ff143f2e70b5c6a79c6469e0eeb40824e07a7277f59aabfda",
+ "aarch64-unknown-linux-gnu": "236a300f386ead02ca98dbddbc026ff4ef4de6701a394106e291ff8b75445ee1",
+ "x86_64-apple-darwin": "fcf04532e644644213977242cd724fe5e84c0a5ac92ae038e07f1b01b474fca3",
+ "x86_64-pc-windows-msvc": "a9d203e78caed94de368d154e841610cef6f6b484738573f4ae9059d37e898a5",
+ "x86_64-unknown-linux-gnu": "1e8a3babd1500111359b0f5675d770984bcbcb2cc8890b117394f0ed342fb9ec",
+ },
+ "strip_prefix": "python",
+ },
"3.9.10": {
"url": "20220227/cpython-{python_version}+20220227-{platform}-{build}.tar.gz",
"sha256": {
@@ -153,6 +175,32 @@ TOOL_VERSIONS = {
},
"strip_prefix": "python",
},
+ "3.9.17": {
+ "url": "20230726/cpython-{python_version}+20230726-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "73dbe2d702210b566221da9265acc274ba15275c5d0d1fa327f44ad86cde9aa1",
+ "aarch64-unknown-linux-gnu": "b77012ddaf7e0673e4aa4b1c5085275a06eee2d66f33442b5c54a12b62b96cbe",
+ "ppc64le-unknown-linux-gnu": "c591a28d943dce5cf9833e916125fdfbeb3120270c4866ee214493ccb5b83c3c",
+ "s390x-unknown-linux-gnu": "01454d7cc7c9c2fccde42ba868c4f372eaaafa48049d49dd94c9cf2875f497e6",
+ "x86_64-apple-darwin": "dfe1bea92c94b9cb779288b0b06e39157c5ff7e465cdd24032ac147c2af485c0",
+ "x86_64-pc-windows-msvc": "9b9a1e21eff29dcf043cea38180cf8ca3604b90117d00062a7b31605d4157714",
+ "x86_64-unknown-linux-gnu": "26c4a712b4b8e11ed5c027db5654eb12927c02da4857b777afb98f7a930ce637",
+ },
+ "strip_prefix": "python",
+ },
+ "3.9.18": {
+ "url": "20231002/cpython-{python_version}+20231002-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "fdc4054837e37b69798c2ef796222a480bc1f80e8ad3a01a95d0168d8282a007",
+ "aarch64-unknown-linux-gnu": "1e0a3e8ce8e58901a259748c0ab640d2b8294713782d14229e882c6898b2fb36",
+ "ppc64le-unknown-linux-gnu": "101c38b22fb2f5a0945156da4259c8e9efa0c08de9d7f59afa51e7ce6e22a1cc",
+ "s390x-unknown-linux-gnu": "eee31e55ffbc1f460d7b17f05dd89e45a2636f374a6f8dc29ea13d0497f7f586",
+ "x86_64-apple-darwin": "82231cb77d4a5c8081a1a1d5b8ae440abe6993514eb77a926c826e9a69a94fb1",
+ "x86_64-pc-windows-msvc": "02ea7bb64524886bd2b05d6b6be4401035e4ba4319146f274f0bcd992822cd75",
+ "x86_64-unknown-linux-gnu": "f3ff38b1ccae7dcebd8bbf2e533c9a984fac881de0ffd1636fbb61842bd924de",
+ },
+ "strip_prefix": "python",
+ },
"3.10.2": {
"url": "20220227/cpython-{python_version}+20220227-{platform}-{build}.tar.gz",
"sha256": {
@@ -220,6 +268,32 @@ TOOL_VERSIONS = {
},
"strip_prefix": "python",
},
+ "3.10.12": {
+ "url": "20230726/cpython-{python_version}+20230726-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "bc66c706ea8c5fc891635fda8f9da971a1a901d41342f6798c20ad0b2a25d1d6",
+ "aarch64-unknown-linux-gnu": "fee80e221663eca5174bd794cb5047e40d3910dbeadcdf1f09d405a4c1c15fe4",
+ "ppc64le-unknown-linux-gnu": "bb5e8cb0d2e44241725fa9b342238245503e7849917660006b0246a9c97b1d6c",
+ "s390x-unknown-linux-gnu": "8d33d435ae6fb93ded7fc26798cc0a1a4f546a4e527012a1e2909cc314b332df",
+ "x86_64-apple-darwin": "8a6e3ed973a671de468d9c691ed9cb2c3a4858c5defffcf0b08969fba9c1dd04",
+ "x86_64-pc-windows-msvc": "c1a31c353ca44de7d1b1a3b6c55a823e9c1eed0423d4f9f66e617bdb1b608685",
+ "x86_64-unknown-linux-gnu": "a476dbca9184df9fc69fe6309cda5ebaf031d27ca9e529852437c94ec1bc43d3",
+ },
+ "strip_prefix": "python",
+ },
+ "3.10.13": {
+ "url": "20231002/cpython-{python_version}+20231002-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "fd027b1dedf1ea034cdaa272e91771bdf75ddef4c8653b05d224a0645aa2ca3c",
+ "aarch64-unknown-linux-gnu": "8675915ff454ed2f1597e27794bc7df44f5933c26b94aa06af510fe91b58bb97",
+ "ppc64le-unknown-linux-gnu": "f3f9c43eec1a0c3f72845d0b705da17a336d3906b7df212d2640b8f47e8ff375",
+ "s390x-unknown-linux-gnu": "859f6cfe9aedb6e8858892fdc124037e83ab05f28d42a7acd314c6a16d6bd66c",
+ "x86_64-apple-darwin": "be0b19b6af1f7d8c667e5abef5505ad06cf72e5a11bb5844970c395a7e5b1275",
+ "x86_64-pc-windows-msvc": "b8d930ce0d04bda83037ad3653d7450f8907c88e24bb8255a29b8dab8930d6f1",
+ "x86_64-unknown-linux-gnu": "5d0429c67c992da19ba3eb58b3acd0b35ec5e915b8cae9a4aa8ca565c423847a",
+ },
+ "strip_prefix": "python",
+ },
"3.11.1": {
"url": "20230116/cpython-{python_version}+20230116-{platform}-{build}.tar.gz",
"sha256": {
@@ -243,14 +317,67 @@ TOOL_VERSIONS = {
},
"strip_prefix": "python",
},
+ "3.11.4": {
+ "url": "20230726/cpython-{python_version}+20230726-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "cb6d2948384a857321f2aa40fa67744cd9676a330f08b6dad7070bda0b6120a4",
+ "aarch64-unknown-linux-gnu": "2e84fc53f4e90e11963281c5c871f593abcb24fc796a50337fa516be99af02fb",
+ "ppc64le-unknown-linux-gnu": "df7b92ed9cec96b3bb658fb586be947722ecd8e420fb23cee13d2e90abcfcf25",
+ "s390x-unknown-linux-gnu": "e477f0749161f9aa7887964f089d9460a539f6b4a8fdab5166f898210e1a87a4",
+ "x86_64-apple-darwin": "47e1557d93a42585972772e82661047ca5f608293158acb2778dccf120eabb00",
+ "x86_64-pc-windows-msvc": "878614c03ea38538ae2f758e36c85d2c0eb1eaaca86cd400ff8c76693ee0b3e1",
+ "x86_64-unknown-linux-gnu": "e26247302bc8e9083a43ce9e8dd94905b40d464745b1603041f7bc9a93c65d05",
+ },
+ "strip_prefix": "python",
+ },
+ "3.11.5": {
+ "url": "20230826/cpython-{python_version}+20230826-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "dab64b3580118ad2073babd7c29fd2053b616479df5c107d31fe2af1f45e948b",
+ "aarch64-unknown-linux-gnu": "bb5c5d1ea0f199fe2d3f0996fff4b48ca6ddc415a3dbd98f50bff7fce48aac80",
+ "ppc64le-unknown-linux-gnu": "14121b53e9c8c6d0741f911ae00102a35adbcf5c3cdf732687ef7617b7d7304d",
+ "s390x-unknown-linux-gnu": "fe459da39874443579d6fe88c68777c6d3e331038e1fb92a0451879fb6beb16d",
+ "x86_64-apple-darwin": "4a4efa7378c72f1dd8ebcce1afb99b24c01b07023aa6b8fea50eaedb50bf2bfc",
+ "x86_64-pc-windows-msvc": "00f002263efc8aea896bcfaaf906b1f4dab3e5cd3db53e2b69ab9a10ba220b97",
+ "x86_64-unknown-linux-gnu": "fbed6f7694b2faae5d7c401a856219c945397f772eea5ca50c6eb825cbc9d1e1",
+ },
+ "strip_prefix": "python",
+ },
+ "3.11.6": {
+ "url": "20231002/cpython-{python_version}+20231002-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "916c35125b5d8323a21526d7a9154ca626453f63d0878e95b9f613a95006c990",
+ "aarch64-unknown-linux-gnu": "3e26a672df17708c4dc928475a5974c3fb3a34a9b45c65fb4bd1e50504cc84ec",
+ "ppc64le-unknown-linux-gnu": "7937035f690a624dba4d014ffd20c342e843dd46f89b0b0a1e5726b85deb8eaf",
+ "s390x-unknown-linux-gnu": "f9f19823dba3209cedc4647b00f46ed0177242917db20fb7fb539970e384531c",
+ "x86_64-apple-darwin": "178cb1716c2abc25cb56ae915096c1a083e60abeba57af001996e8bc6ce1a371",
+ "x86_64-pc-windows-msvc": "3933545e6d41462dd6a47e44133ea40995bc6efeed8c2e4cbdf1a699303e95ea",
+ "x86_64-unknown-linux-gnu": "ee37a7eae6e80148c7e3abc56e48a397c1664f044920463ad0df0fc706eacea8",
+ },
+ "strip_prefix": "python",
+ },
+ "3.12.0": {
+ "url": "20231002/cpython-{python_version}+20231002-{platform}-{build}.tar.gz",
+ "sha256": {
+ "aarch64-apple-darwin": "4734a2be2becb813830112c780c9879ac3aff111a0b0cd590e65ec7465774d02",
+ "aarch64-unknown-linux-gnu": "bccfe67cf5465a3dfb0336f053966e2613a9bc85a6588c2fcf1366ef930c4f88",
+ "ppc64le-unknown-linux-gnu": "b5dae075467ace32c594c7877fe6ebe0837681f814601d5d90ba4c0dfd87a1f2",
+ "s390x-unknown-linux-gnu": "5681621349dd85d9726d1b67c84a9686ce78f72e73a6f9e4cc4119911655759e",
+ "x86_64-apple-darwin": "5a9e88c8aa52b609d556777b52ebde464ae4b4f77e4aac4eb693af57395c9abf",
+ "x86_64-pc-windows-msvc": "facfaa1fbc8653f95057f3c4a0f8aa833dab0e0b316e24ee8686bc761d4b4f8d",
+ "x86_64-unknown-linux-gnu": "e51a5293f214053ddb4645b2c9f84542e2ef86870b8655704367bd4b29d39fe9",
+ },
+ "strip_prefix": "python",
+ },
}
# buildifier: disable=unsorted-dict-items
MINOR_MAPPING = {
- "3.8": "3.8.15",
- "3.9": "3.9.16",
- "3.10": "3.10.9",
- "3.11": "3.11.1",
+ "3.8": "3.8.18",
+ "3.9": "3.9.18",
+ "3.10": "3.10.13",
+ "3.11": "3.11.6",
+ "3.12": "3.12.0",
}
PLATFORMS = {
@@ -286,6 +413,17 @@ PLATFORMS = {
# repository_ctx.execute(["uname", "-m"]).stdout.strip()
arch = "ppc64le",
),
+ "s390x-unknown-linux-gnu": struct(
+ compatible_with = [
+ "@platforms//os:linux",
+ "@platforms//cpu:s390x",
+ ],
+ os_name = LINUX_NAME,
+ # Note: this string differs between OSX and Linux
+ # Matches the value returned from:
+ # repository_ctx.execute(["uname", "-m"]).stdout.strip()
+ arch = "s390x",
+ ),
"x86_64-apple-darwin": struct(
compatible_with = [
"@platforms//os:macos",
diff --git a/sphinxdocs/BUILD.bazel b/sphinxdocs/BUILD.bazel
new file mode 100644
index 0000000..cd1a1fb
--- /dev/null
+++ b/sphinxdocs/BUILD.bazel
@@ -0,0 +1,50 @@
+# 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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//sphinxdocs/private:sphinx.bzl", "repeated_string_list_flag")
+
+package(
+ default_visibility = ["//:__subpackages__"],
+)
+
+# Additional -D values to add to every Sphinx build.
+# This is usually used to override the version when building
+repeated_string_list_flag(
+ name = "extra_defines",
+ build_setting_default = [],
+)
+
+repeated_string_list_flag(
+ name = "extra_env",
+ build_setting_default = [],
+)
+
+bzl_library(
+ name = "sphinx_bzl",
+ srcs = ["sphinx.bzl"],
+ deps = ["//sphinxdocs/private:sphinx_bzl"],
+)
+
+bzl_library(
+ name = "sphinx_stardoc_bzl",
+ srcs = ["sphinx_stardoc.bzl"],
+ deps = ["//sphinxdocs/private:sphinx_stardoc_bzl"],
+)
+
+bzl_library(
+ name = "readthedocs_bzl",
+ srcs = ["readthedocs.bzl"],
+ deps = ["//sphinxdocs/private:readthedocs_bzl"],
+)
diff --git a/sphinxdocs/private/BUILD.bazel b/sphinxdocs/private/BUILD.bazel
new file mode 100644
index 0000000..01758b3
--- /dev/null
+++ b/sphinxdocs/private/BUILD.bazel
@@ -0,0 +1,99 @@
+# 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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//python:proto.bzl", "py_proto_library")
+load("//python:py_binary.bzl", "py_binary")
+load("//python:py_library.bzl", "py_library")
+
+package(
+ default_visibility = ["//sphinxdocs:__subpackages__"],
+)
+
+# These are only exported because they're passed as files to the //sphinxdocs
+# macros, and thus must be visible to other packages. They should only be
+# referenced by the //sphinxdocs macros.
+exports_files(
+ [
+ "func_template.vm",
+ "header_template.vm",
+ "provider_template.vm",
+ "readthedocs_install.py",
+ "rule_template.vm",
+ "sphinx_build.py",
+ "sphinx_server.py",
+ ],
+ visibility = ["//:__subpackages__"],
+)
+
+bzl_library(
+ name = "sphinx_bzl",
+ srcs = ["sphinx.bzl"],
+ deps = [
+ "//python:py_binary_bzl",
+ "@bazel_skylib//lib:paths",
+ "@bazel_skylib//lib:types",
+ "@bazel_skylib//rules:build_test",
+ "@io_bazel_stardoc//stardoc:stardoc_lib",
+ ],
+)
+
+bzl_library(
+ name = "sphinx_stardoc_bzl",
+ srcs = ["sphinx_stardoc.bzl"],
+ deps = [
+ "//python/private:util_bzl",
+ "@bazel_skylib//lib:types",
+ "@bazel_skylib//rules:build_test",
+ "@io_bazel_stardoc//stardoc:stardoc_lib",
+ ],
+)
+
+bzl_library(
+ name = "readthedocs_bzl",
+ srcs = ["readthedocs.bzl"],
+ deps = ["//python:py_binary_bzl"],
+)
+
+py_binary(
+ name = "inventory_builder",
+ srcs = ["inventory_builder.py"],
+ # Only public because it's an implicit attribute
+ visibility = ["//:__subpackages__"],
+)
+
+py_binary(
+ name = "proto_to_markdown",
+ srcs = ["proto_to_markdown.py"],
+ # Only public because it's an implicit attribute
+ visibility = ["//:__subpackages__"],
+ deps = [":proto_to_markdown_lib"],
+)
+
+py_library(
+ name = "proto_to_markdown_lib",
+ srcs = ["proto_to_markdown.py"],
+ # Only public because it's an implicit attribute
+ visibility = ["//:__subpackages__"],
+ deps = [
+ ":stardoc_output_proto_py_pb2",
+ ],
+)
+
+py_proto_library(
+ name = "stardoc_output_proto_py_pb2",
+ deps = [
+ "@io_bazel_stardoc//stardoc/proto:stardoc_output_proto",
+ ],
+)
diff --git a/sphinxdocs/private/inventory_builder.py b/sphinxdocs/private/inventory_builder.py
new file mode 100644
index 0000000..850d944
--- /dev/null
+++ b/sphinxdocs/private/inventory_builder.py
@@ -0,0 +1,24 @@
+import pathlib
+import sys
+import zlib
+
+
+def main(args):
+ in_path = pathlib.Path(args.pop(0))
+ out_path = pathlib.Path(args.pop(0))
+
+ data = in_path.read_bytes()
+ offset = 0
+ for _ in range(4):
+ offset = data.index(b"\n", offset) + 1
+
+ compressed_bytes = zlib.compress(data[offset:])
+ with out_path.open(mode="bw") as fp:
+ fp.write(data[:offset])
+ fp.write(compressed_bytes)
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/sphinxdocs/private/proto_to_markdown.py b/sphinxdocs/private/proto_to_markdown.py
new file mode 100644
index 0000000..18d4e1e
--- /dev/null
+++ b/sphinxdocs/private/proto_to_markdown.py
@@ -0,0 +1,488 @@
+# 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 argparse
+import io
+import itertools
+import pathlib
+import sys
+import textwrap
+from typing import Callable, TextIO, TypeVar
+
+from stardoc.proto import stardoc_output_pb2
+
+_AttributeType = stardoc_output_pb2.AttributeType
+
+_T = TypeVar("_T")
+
+
+def _anchor_id(text: str) -> str:
+ # MyST/Sphinx's markdown processing doesn't like dots in anchor ids.
+ return "#" + text.replace(".", "_").lower()
+
+
+# Create block attribute line.
+# See https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#block-attributes
+def _block_attrs(*attrs: str) -> str:
+ return "{" + " ".join(attrs) + "}\n"
+
+
+def _link(display: str, link: str = "", *, ref: str = "", classes: str = "") -> str:
+ if ref:
+ ref = f"[{ref}]"
+ if link:
+ link = f"({link})"
+ if classes:
+ classes = "{" + classes + "}"
+ return f"[{display}]{ref}{link}{classes}"
+
+
+def _span(display: str, classes: str = ".span") -> str:
+ return f"[{display}]{{" + classes + "}"
+
+
+def _link_here_icon(anchor: str) -> str:
+ # The headerlink class activates some special logic to show/hide
+ # text upon mouse-over; it's how headings show a clickable link.
+ return _link("¶", anchor, classes=".headerlink")
+
+
+def _inline_anchor(anchor: str) -> str:
+ return _span("", anchor)
+
+
+def _indent_block_text(text: str) -> str:
+ return text.strip().replace("\n", "\n ")
+
+
+def _join_csv_and(values: list[str]) -> str:
+ if len(values) == 1:
+ return values[0]
+
+ values = list(values)
+ values[-1] = "and " + values[-1]
+ return ", ".join(values)
+
+
+def _position_iter(values: list[_T]) -> tuple[bool, bool, _T]:
+ for i, value in enumerate(values):
+ yield i == 0, i == len(values) - 1, value
+
+
+class _MySTRenderer:
+ def __init__(
+ self,
+ module: stardoc_output_pb2.ModuleInfo,
+ out_stream: TextIO,
+ public_load_path: str,
+ ):
+ self._module = module
+ self._out_stream = out_stream
+ self._public_load_path = public_load_path
+
+ def render(self):
+ self._render_module(self._module)
+
+ def _render_module(self, module: stardoc_output_pb2.ModuleInfo):
+ if self._public_load_path:
+ bzl_path = self._public_load_path
+ else:
+ bzl_path = "//" + self._module.file.split("//")[1]
+ self._write(
+ f"# {bzl_path}\n",
+ "\n",
+ module.module_docstring.strip(),
+ "\n\n",
+ )
+
+ # Sort the objects by name
+ objects = itertools.chain(
+ ((r.rule_name, r, self._render_rule) for r in module.rule_info),
+ ((p.provider_name, p, self._render_provider) for p in module.provider_info),
+ ((f.function_name, f, self._render_func) for f in module.func_info),
+ ((a.aspect_name, a, self._render_aspect) for a in module.aspect_info),
+ (
+ (m.extension_name, m, self._render_module_extension)
+ for m in module.module_extension_info
+ ),
+ (
+ (r.rule_name, r, self._render_repository_rule)
+ for r in module.repository_rule_info
+ ),
+ )
+
+ objects = sorted(objects, key=lambda v: v[0].lower())
+
+ for _, obj, func in objects:
+ func(obj)
+ self._write("\n")
+
+ def _render_aspect(self, aspect: stardoc_output_pb2.AspectInfo):
+ aspect_anchor = _anchor_id(aspect.aspect_name)
+ self._write(
+ _block_attrs(".starlark-object"),
+ f"## {aspect.aspect_name}\n\n",
+ "_Propagates on attributes:_ ", # todo add link here
+ ", ".join(sorted(f"`{attr}`" for attr in aspect.aspect_attribute)),
+ "\n\n",
+ aspect.doc_string.strip(),
+ "\n\n",
+ )
+
+ if aspect.attribute:
+ self._render_attributes(aspect_anchor, aspect.attribute)
+ self._write("\n")
+
+ def _render_module_extension(self, mod_ext: stardoc_output_pb2.ModuleExtensionInfo):
+ self._write(
+ _block_attrs(".starlark-object"),
+ f"## {mod_ext.extension_name}\n\n",
+ )
+
+ self._write(mod_ext.doc_string.strip(), "\n\n")
+
+ mod_ext_anchor = _anchor_id(mod_ext.extension_name)
+ for tag in mod_ext.tag_class:
+ tag_name = f"{mod_ext.extension_name}.{tag.tag_name}"
+ tag_anchor = f"{mod_ext_anchor}_{tag.tag_name}"
+ self._write(
+ _block_attrs(".starlark-module-extension-tag-class"),
+ f"### {tag_name}\n\n",
+ )
+ self._render_signature(
+ tag_name,
+ tag_anchor,
+ tag.attribute,
+ get_name=lambda a: a.name,
+ get_default=lambda a: a.default_value,
+ )
+
+ self._write(tag.doc_string.strip(), "\n\n")
+ self._render_attributes(tag_anchor, tag.attribute)
+ self._write("\n")
+
+ def _render_repository_rule(self, repo_rule: stardoc_output_pb2.RepositoryRuleInfo):
+ self._write(
+ _block_attrs(".starlark-object"),
+ f"## {repo_rule.rule_name}\n\n",
+ )
+ repo_anchor = _anchor_id(repo_rule.rule_name)
+ self._render_signature(
+ repo_rule.rule_name,
+ repo_anchor,
+ repo_rule.attribute,
+ get_name=lambda a: a.name,
+ get_default=lambda a: a.default_value,
+ )
+ self._write(repo_rule.doc_string.strip(), "\n\n")
+ if repo_rule.attribute:
+ self._render_attributes(repo_anchor, repo_rule.attribute)
+ if repo_rule.environ:
+ self._write(
+ "**ENVIRONMENT VARIABLES** ",
+ _link_here_icon(repo_anchor + "_env"),
+ "\n",
+ )
+ for name in sorted(repo_rule.environ):
+ self._write(f"* `{name}`\n")
+ self._write("\n")
+
+ def _render_rule(self, rule: stardoc_output_pb2.RuleInfo):
+ rule_name = rule.rule_name
+ rule_anchor = _anchor_id(rule_name)
+ self._write(
+ _block_attrs(".starlark-object"),
+ f"## {rule_name}\n\n",
+ )
+
+ self._render_signature(
+ rule_name,
+ rule_anchor,
+ rule.attribute,
+ get_name=lambda r: r.name,
+ get_default=lambda r: r.default_value,
+ )
+
+ self._write(rule.doc_string.strip(), "\n\n")
+
+ if len(rule.advertised_providers.provider_name) == 0:
+ self._write("_Provides_: no providers advertised.")
+ else:
+ self._write(
+ "_Provides_: ",
+ ", ".join(rule.advertised_providers.provider_name),
+ )
+ self._write("\n\n")
+
+ if rule.attribute:
+ self._render_attributes(rule_anchor, rule.attribute)
+
+ def _rule_attr_type_string(self, attr: stardoc_output_pb2.AttributeInfo) -> str:
+ if attr.type == _AttributeType.NAME:
+ return _link("Name", ref="target-name")
+ elif attr.type == _AttributeType.INT:
+ return _link("int", ref="int")
+ elif attr.type == _AttributeType.LABEL:
+ return _link("label", ref="attr-label")
+ elif attr.type == _AttributeType.STRING:
+ return _link("string", ref="str")
+ elif attr.type == _AttributeType.STRING_LIST:
+ return "list of " + _link("string", ref="str")
+ elif attr.type == _AttributeType.INT_LIST:
+ return "list of " + _link("int", ref="int")
+ elif attr.type == _AttributeType.LABEL_LIST:
+ return "list of " + _link("label", ref="attr-label") + "s"
+ elif attr.type == _AttributeType.BOOLEAN:
+ return _link("bool", ref="bool")
+ elif attr.type == _AttributeType.LABEL_STRING_DICT:
+ return "dict of {key} to {value}".format(
+ key=_link("label", ref="attr-label"), value=_link("string", ref="str")
+ )
+ elif attr.type == _AttributeType.STRING_DICT:
+ return "dict of {key} to {value}".format(
+ key=_link("string", ref="str"), value=_link("string", ref="str")
+ )
+ elif attr.type == _AttributeType.STRING_LIST_DICT:
+ return "dict of {key} to list of {value}".format(
+ key=_link("string", ref="str"), value=_link("string", ref="str")
+ )
+ elif attr.type == _AttributeType.OUTPUT:
+ return _link("label", ref="attr-label")
+ elif attr.type == _AttributeType.OUTPUT_LIST:
+ return "list of " + _link("label", ref="attr-label")
+ else:
+ # If we get here, it means the value was unknown for some reason.
+ # Rather than error, give some somewhat understandable value.
+ return _AttributeType.Name(attr.type)
+
+ def _render_func(self, func: stardoc_output_pb2.StarlarkFunctionInfo):
+ func_name = func.function_name
+ func_anchor = _anchor_id(func_name)
+ self._write(
+ _block_attrs(".starlark-object"),
+ f"## {func_name}\n\n",
+ )
+
+ parameters = [param for param in func.parameter if param.name != "self"]
+
+ self._render_signature(
+ func_name,
+ func_anchor,
+ parameters,
+ get_name=lambda p: p.name,
+ get_default=lambda p: p.default_value,
+ )
+
+ self._write(func.doc_string.strip(), "\n\n")
+
+ if parameters:
+ self._write(
+ _block_attrs(f"{func_anchor}_parameters"),
+ "**PARAMETERS** ",
+ _link_here_icon(f"{func_anchor}_parameters"),
+ "\n\n",
+ )
+ entries = []
+ for param in parameters:
+ entries.append(
+ [
+ f"{func_anchor}_{param.name}",
+ param.name,
+ f"(_default `{param.default_value}`_) "
+ if param.default_value
+ else "",
+ param.doc_string if param.doc_string else "_undocumented_",
+ ]
+ )
+ self._render_field_list(entries)
+
+ if getattr(func, "return").doc_string:
+ return_doc = _indent_block_text(getattr(func, "return").doc_string)
+ self._write(
+ _block_attrs(f"{func_anchor}_returns"),
+ "RETURNS",
+ _link_here_icon(func_anchor + "_returns"),
+ "\n",
+ ": ",
+ return_doc,
+ "\n",
+ )
+ if func.deprecated.doc_string:
+ self._write(
+ "\n\n**DEPRECATED**\n\n", func.deprecated.doc_string.strip(), "\n"
+ )
+
+ def _render_provider(self, provider: stardoc_output_pb2.ProviderInfo):
+ self._write(
+ _block_attrs(".starlark-object"),
+ f"## {provider.provider_name}\n\n",
+ )
+
+ provider_anchor = _anchor_id(provider.provider_name)
+ self._render_signature(
+ provider.provider_name,
+ provider_anchor,
+ provider.field_info,
+ get_name=lambda f: f.name,
+ )
+
+ self._write(provider.doc_string.strip(), "\n\n")
+
+ if provider.field_info:
+ self._write(
+ _block_attrs(provider_anchor),
+ "**FIELDS** ",
+ _link_here_icon(provider_anchor + "_fields"),
+ "\n",
+ "\n",
+ )
+ entries = []
+ for field in provider.field_info:
+ entries.append(
+ [
+ f"{provider_anchor}_{field.name}",
+ field.name,
+ field.doc_string,
+ ]
+ )
+ self._render_field_list(entries)
+
+ def _render_attributes(
+ self, base_anchor: str, attributes: list[stardoc_output_pb2.AttributeInfo]
+ ):
+ self._write(
+ _block_attrs(f"{base_anchor}_attributes"),
+ "**ATTRIBUTES** ",
+ _link_here_icon(f"{base_anchor}_attributes"),
+ "\n",
+ )
+ entries = []
+ for attr in attributes:
+ anchor = f"{base_anchor}_{attr.name}"
+ required = "required" if attr.mandatory else "optional"
+ attr_type = self._rule_attr_type_string(attr)
+ default = f", default `{attr.default_value}`" if attr.default_value else ""
+ providers_parts = []
+ if attr.provider_name_group:
+ providers_parts.append("\n\n_Required providers_: ")
+ if len(attr.provider_name_group) == 1:
+ provider_group = attr.provider_name_group[0]
+ if len(provider_group.provider_name) == 1:
+ providers_parts.append(provider_group.provider_name[0])
+ else:
+ providers_parts.extend(
+ ["all of ", _join_csv_and(provider_group.provider_name)]
+ )
+ elif len(attr.provider_name_group) > 1:
+ providers_parts.append("any of \n")
+ for group in attr.provider_name_group:
+ providers_parts.extend(["* ", _join_csv_and(group.provider_name)])
+ if providers_parts:
+ providers_parts.append("\n")
+
+ entries.append(
+ [
+ anchor,
+ attr.name,
+ f"_({required} {attr_type}{default})_\n",
+ attr.doc_string,
+ *providers_parts,
+ ]
+ )
+ self._render_field_list(entries)
+
+ def _render_signature(
+ self,
+ name: str,
+ base_anchor: str,
+ parameters: list[_T],
+ *,
+ get_name: Callable[_T, str],
+ get_default: Callable[_T, str] = lambda v: None,
+ ):
+ self._write(_block_attrs(".starlark-signature"), name, "(")
+ for _, is_last, param in _position_iter(parameters):
+ param_name = get_name(param)
+ self._write(_link(param_name, f"{base_anchor}_{param_name}"))
+ default_value = get_default(param)
+ if default_value:
+ self._write(f"={default_value}")
+ if not is_last:
+ self._write(",\n")
+ self._write(")\n\n")
+
+ def _render_field_list(self, entries: list[list[str]]):
+ """Render a list of field lists.
+
+ Args:
+ entries: list of field list entries. Each element is 3
+ pieces: an anchor, field description, and one or more
+ text strings for the body of the field list entry.
+ """
+ for anchor, description, *body_pieces in entries:
+ body_pieces = [_block_attrs(anchor), *body_pieces]
+ self._write(
+ ":",
+ _span(description + _link_here_icon(anchor)),
+ ":\n ",
+ # The text has to be indented to be associated with the block correctly.
+ "".join(body_pieces).strip().replace("\n", "\n "),
+ "\n",
+ )
+ # Ensure there is an empty line after the field list, otherwise
+ # the next line of content will fold into the field list
+ self._write("\n")
+
+ def _write(self, *lines: str):
+ self._out_stream.writelines(lines)
+
+
+def _convert(
+ *,
+ proto: pathlib.Path,
+ output: pathlib.Path,
+ footer: pathlib.Path,
+ public_load_path: str,
+):
+ if footer:
+ footer_content = footer.read_text()
+
+ module = stardoc_output_pb2.ModuleInfo.FromString(proto.read_bytes())
+ with output.open("wt", encoding="utf8") as out_stream:
+ _MySTRenderer(module, out_stream, public_load_path).render()
+ out_stream.write(footer_content)
+
+
+def _create_parser():
+ parser = argparse.ArgumentParser(fromfile_prefix_chars="@")
+ parser.add_argument("--footer", dest="footer", type=pathlib.Path)
+ parser.add_argument("--proto", dest="proto", type=pathlib.Path)
+ parser.add_argument("--output", dest="output", type=pathlib.Path)
+ parser.add_argument("--public-load-path", dest="public_load_path")
+ return parser
+
+
+def main(args):
+ options = _create_parser().parse_args(args)
+ _convert(
+ proto=options.proto,
+ output=options.output,
+ footer=options.footer,
+ public_load_path=options.public_load_path,
+ )
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/sphinxdocs/private/readthedocs.bzl b/sphinxdocs/private/readthedocs.bzl
new file mode 100644
index 0000000..3cab75b
--- /dev/null
+++ b/sphinxdocs/private/readthedocs.bzl
@@ -0,0 +1,48 @@
+# 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.
+"""Starlark rules for integrating Sphinx and Readthedocs."""
+
+load("//python:py_binary.bzl", "py_binary")
+load("//python/private:util.bzl", "add_tag") # buildifier: disable=bzl-visibility
+
+_INSTALL_MAIN_SRC = Label("//sphinxdocs/private:readthedocs_install.py")
+
+def readthedocs_install(name, docs, **kwargs):
+ """Run a program to copy Sphinx doc files into readthedocs output directories.
+
+ This is intended to be run using `bazel run` during the readthedocs
+ build process when the build process is overridden. See
+ https://docs.readthedocs.io/en/stable/build-customization.html#override-the-build-process
+ for more information.
+
+ Args:
+ name: (str) name of the installer
+ docs: (label list) list of targets that generate directories to copy
+ into the directories readthedocs expects final output in. This
+ is typically a single `sphinx_stardocs` target.
+ **kwargs: (dict) additional kwargs to pass onto the installer
+ """
+ add_tag(kwargs, "@rules_python//sphinxdocs:readthedocs_install")
+ py_binary(
+ name = name,
+ srcs = [_INSTALL_MAIN_SRC],
+ main = _INSTALL_MAIN_SRC,
+ data = docs,
+ args = [
+ "$(rlocationpaths {})".format(d)
+ for d in docs
+ ],
+ deps = ["//python/runfiles"],
+ **kwargs
+ )
diff --git a/sphinxdocs/private/readthedocs_install.py b/sphinxdocs/private/readthedocs_install.py
new file mode 100644
index 0000000..9b1f2a8
--- /dev/null
+++ b/sphinxdocs/private/readthedocs_install.py
@@ -0,0 +1,27 @@
+import os
+import pathlib
+import shutil
+import sys
+
+from python import runfiles
+
+
+def main(args):
+ if not args:
+ raise ValueError("Empty args: expected paths to copy")
+
+ if not (install_to := os.environ.get("READTHEDOCS_OUTPUT")):
+ raise ValueError("READTHEDOCS_OUTPUT environment variable not set")
+
+ install_to = pathlib.Path(install_to)
+
+ rf = runfiles.Create()
+ for doc_dir_runfiles_path in args:
+ doc_dir_path = pathlib.Path(rf.Rlocation(doc_dir_runfiles_path))
+ dest = install_to / doc_dir_path.name
+ print(f"Copying {doc_dir_path} to {dest}")
+ shutil.copytree(src=doc_dir_path, dst=dest, dirs_exist_ok=True)
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/sphinxdocs/private/sphinx.bzl b/sphinxdocs/private/sphinx.bzl
new file mode 100644
index 0000000..daff02d
--- /dev/null
+++ b/sphinxdocs/private/sphinx.bzl
@@ -0,0 +1,336 @@
+# 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.
+
+"""Implementation of sphinx rules."""
+
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load("//python:py_binary.bzl", "py_binary")
+load("//python/private:util.bzl", "add_tag", "copy_propagating_kwargs") # buildifier: disable=bzl-visibility
+
+_SPHINX_BUILD_MAIN_SRC = Label("//sphinxdocs/private:sphinx_build.py")
+_SPHINX_SERVE_MAIN_SRC = Label("//sphinxdocs/private:sphinx_server.py")
+
+def sphinx_build_binary(name, py_binary_rule = py_binary, **kwargs):
+ """Create an executable with the sphinx-build command line interface.
+
+ The `deps` must contain the sphinx library and any other extensions Sphinx
+ needs at runtime.
+
+ Args:
+ name: (str) name of the target. The name "sphinx-build" is the
+ conventional name to match what Sphinx itself uses.
+ py_binary_rule: (optional callable) A `py_binary` compatible callable
+ for creating the target. If not set, the regular `py_binary`
+ rule is used. This allows using the version-aware rules, or
+ other alternative implementations.
+ **kwargs: Additional kwargs to pass onto `py_binary`. The `srcs` and
+ `main` attributes must not be specified.
+ """
+ add_tag(kwargs, "@rules_python//sphinxdocs:sphinx_build_binary")
+ py_binary_rule(
+ name = name,
+ srcs = [_SPHINX_BUILD_MAIN_SRC],
+ main = _SPHINX_BUILD_MAIN_SRC,
+ **kwargs
+ )
+
+def sphinx_docs(
+ name,
+ *,
+ srcs = [],
+ renamed_srcs = {},
+ sphinx,
+ config,
+ formats,
+ strip_prefix = "",
+ extra_opts = [],
+ **kwargs):
+ """Generate docs using Sphinx.
+
+ This generates three public targets:
+ * `<name>`: The output of this target is a directory for each
+ format Sphinx creates. This target also has a separate output
+ group for each format. e.g. `--output_group=html` will only build
+ the "html" format files.
+ * `<name>_define`: A multi-string flag to add additional `-D`
+ arguments to the Sphinx invocation. This is useful for overriding
+ the version information in the config file for builds.
+ * `<name>.serve`: A binary that locally serves the HTML output. This
+ allows previewing docs during development.
+
+ Args:
+ name: (str) name of the docs rule.
+ srcs: (label list) The source files for Sphinx to process.
+ renamed_srcs: (label_keyed_string_dict) Doc source files for Sphinx that
+ are renamed. This is typically used for files elsewhere, such as top
+ level files in the repo.
+ sphinx: (label) the Sphinx tool to use for building
+ documentation. Because Sphinx supports various plugins, you must
+ construct your own binary with the necessary dependencies. The
+ `sphinx_build_binary` rule can be used to define such a binary, but
+ any executable supporting the `sphinx-build` command line interface
+ can be used (typically some `py_binary` program).
+ config: (label) the Sphinx config file (`conf.py`) to use.
+ formats: (list of str) the formats (`-b` flag) to generate documentation
+ in. Each format will become an output group.
+ strip_prefix: (str) A prefix to remove from the file paths of the
+ source files. e.g., given `//docs:foo.md`, stripping `docs/`
+ makes Sphinx see `foo.md` in its generated source directory.
+ extra_opts: (list[str]) Additional options to pass onto Sphinx building.
+ **kwargs: (dict) Common attributes to pass onto rules.
+ """
+ add_tag(kwargs, "@rules_python//sphinxdocs:sphinx_docs")
+ common_kwargs = copy_propagating_kwargs(kwargs)
+
+ _sphinx_docs(
+ name = name,
+ srcs = srcs,
+ renamed_srcs = renamed_srcs,
+ sphinx = sphinx,
+ config = config,
+ formats = formats,
+ strip_prefix = strip_prefix,
+ extra_opts = extra_opts,
+ **kwargs
+ )
+
+ html_name = "_{}_html".format(name.lstrip("_"))
+ native.filegroup(
+ name = html_name,
+ srcs = [name],
+ output_group = "html",
+ **common_kwargs
+ )
+ py_binary(
+ name = name + ".serve",
+ srcs = [_SPHINX_SERVE_MAIN_SRC],
+ main = _SPHINX_SERVE_MAIN_SRC,
+ data = [html_name],
+ args = [
+ "$(execpath {})".format(html_name),
+ ],
+ **common_kwargs
+ )
+
+def _sphinx_docs_impl(ctx):
+ source_dir_path, _, inputs = _create_sphinx_source_tree(ctx)
+
+ outputs = {}
+ for format in ctx.attr.formats:
+ output_dir = _run_sphinx(
+ ctx = ctx,
+ format = format,
+ source_path = source_dir_path,
+ output_prefix = paths.join(ctx.label.name, "_build"),
+ inputs = inputs,
+ )
+ outputs[format] = output_dir
+ return [
+ DefaultInfo(files = depset(outputs.values())),
+ OutputGroupInfo(**{
+ format: depset([output])
+ for format, output in outputs.items()
+ }),
+ ]
+
+_sphinx_docs = rule(
+ implementation = _sphinx_docs_impl,
+ attrs = {
+ "config": attr.label(
+ allow_single_file = True,
+ mandatory = True,
+ doc = "Config file for Sphinx",
+ ),
+ "extra_opts": attr.string_list(
+ doc = "Additional options to pass onto Sphinx. These are added after " +
+ "other options, but before the source/output args.",
+ ),
+ "formats": attr.string_list(doc = "Output formats for Sphinx to create."),
+ "renamed_srcs": attr.label_keyed_string_dict(
+ allow_files = True,
+ doc = "Doc source files for Sphinx that are renamed. This is " +
+ "typically used for files elsewhere, such as top level " +
+ "files in the repo.",
+ ),
+ "sphinx": attr.label(
+ executable = True,
+ cfg = "exec",
+ mandatory = True,
+ doc = "Sphinx binary to generate documentation.",
+ ),
+ "srcs": attr.label_list(
+ allow_files = True,
+ doc = "Doc source files for Sphinx.",
+ ),
+ "strip_prefix": attr.string(doc = "Prefix to remove from input file paths."),
+ "_extra_defines_flag": attr.label(default = "//sphinxdocs:extra_defines"),
+ "_extra_env_flag": attr.label(default = "//sphinxdocs:extra_env"),
+ },
+)
+
+def _create_sphinx_source_tree(ctx):
+ # Sphinx only accepts a single directory to read its doc sources from.
+ # Because plain files and generated files are in different directories,
+ # we need to merge the two into a single directory.
+ source_prefix = paths.join(ctx.label.name, "_sources")
+ sphinx_source_files = []
+
+ def _symlink_source(orig):
+ source_rel_path = orig.short_path
+ if source_rel_path.startswith(ctx.attr.strip_prefix):
+ source_rel_path = source_rel_path[len(ctx.attr.strip_prefix):]
+
+ sphinx_source = ctx.actions.declare_file(paths.join(source_prefix, source_rel_path))
+ ctx.actions.symlink(
+ output = sphinx_source,
+ target_file = orig,
+ progress_message = "Symlinking Sphinx source %{input} to %{output}",
+ )
+ sphinx_source_files.append(sphinx_source)
+ return sphinx_source
+
+ # Though Sphinx has a -c flag, we move the config file into the sources
+ # directory to make the config more intuitive because some configuration
+ # options are relative to the config location, not the sources directory.
+ source_conf_file = _symlink_source(ctx.file.config)
+ sphinx_source_dir_path = paths.dirname(source_conf_file.path)
+
+ for orig_file in ctx.files.srcs:
+ _symlink_source(orig_file)
+
+ for src_target, dest in ctx.attr.renamed_srcs.items():
+ src_files = src_target.files.to_list()
+ if len(src_files) != 1:
+ fail("A single file must be specified to be renamed. Target {} " +
+ "generate {} files: {}".format(
+ src_target,
+ len(src_files),
+ src_files,
+ ))
+ sphinx_src = ctx.actions.declare_file(paths.join(source_prefix, dest))
+ ctx.actions.symlink(
+ output = sphinx_src,
+ target_file = src_files[0],
+ progress_message = "Symlinking (renamed) Sphinx source %{input} to %{output}",
+ )
+ sphinx_source_files.append(sphinx_src)
+
+ return sphinx_source_dir_path, source_conf_file, sphinx_source_files
+
+def _run_sphinx(ctx, format, source_path, inputs, output_prefix):
+ output_dir = ctx.actions.declare_directory(paths.join(output_prefix, format))
+
+ args = ctx.actions.args()
+ args.add("-T") # Full tracebacks on error
+ args.add("-b", format)
+ args.add("-q") # Suppress stdout informational text
+ args.add("-j", "auto") # Build in parallel, if possible
+ args.add("-E") # Don't try to use cache files. Bazel can't make use of them.
+ args.add("-a") # Write all files; don't try to detect "changed" files
+ args.add_all(ctx.attr.extra_opts)
+ args.add_all(ctx.attr._extra_defines_flag[_FlagInfo].value, before_each = "-D")
+ args.add(source_path)
+ args.add(output_dir.path)
+
+ env = dict([
+ v.split("=", 1)
+ for v in ctx.attr._extra_env_flag[_FlagInfo].value
+ ])
+
+ ctx.actions.run(
+ executable = ctx.executable.sphinx,
+ arguments = [args],
+ inputs = inputs,
+ outputs = [output_dir],
+ mnemonic = "SphinxBuildDocs",
+ progress_message = "Sphinx building {} for %{{label}}".format(format),
+ env = env,
+ )
+ return output_dir
+
+_FlagInfo = provider(
+ doc = "Provider for a flag value",
+ fields = ["value"],
+)
+
+def _repeated_string_list_flag_impl(ctx):
+ return _FlagInfo(value = ctx.build_setting_value)
+
+repeated_string_list_flag = rule(
+ implementation = _repeated_string_list_flag_impl,
+ build_setting = config.string_list(flag = True, repeatable = True),
+)
+
+def sphinx_inventory(name, src, **kwargs):
+ """Creates a compressed inventory file from an uncompressed on.
+
+ The Sphinx inventory format isn't formally documented, but is understood
+ to be:
+
+ ```
+ # Sphinx inventory version 2
+ # Project: <project name>
+ # Version: <version string>
+ # The remainder of this file is compressed using zlib
+ name domain:role 1 relative-url display name
+ ```
+
+ Where:
+ * `<project name>` is a string. e.g. `Rules Python`
+ * `<version string>` is a string e.g. `1.5.3`
+
+ And there are one or more `name domain:role ...` lines
+ * `name`: the name of the symbol. It can contain special characters,
+ but not spaces.
+ * `domain:role`: The `domain` is usually a language, e.g. `py` or `bzl`.
+ The `role` is usually the type of object, e.g. `class` or `func`. There
+ is no canonical meaning to the values, they are usually domain-specific.
+ * `1` is a number. It affects search priority.
+ * `relative-url` is a URL path relative to the base url in the
+ confg.py intersphinx config.
+ * `display name` is a string. It can contain spaces, or simply be
+ the value `-` to indicate it is the same as `name`
+
+
+ Args:
+ name: [`target-name`] name of the target.
+ src: [`label`] Uncompressed inventory text file.
+ **kwargs: additional kwargs of common attributes.
+ """
+ _sphinx_inventory(name = name, src = src, **kwargs)
+
+def _sphinx_inventory_impl(ctx):
+ output = ctx.actions.declare_file(ctx.label.name + ".inv")
+ args = ctx.actions.args()
+ args.add(ctx.file.src)
+ args.add(output)
+ ctx.actions.run(
+ executable = ctx.executable._builder,
+ arguments = [args],
+ inputs = depset([ctx.file.src]),
+ outputs = [output],
+ )
+ return [DefaultInfo(files = depset([output]))]
+
+_sphinx_inventory = rule(
+ implementation = _sphinx_inventory_impl,
+ attrs = {
+ "src": attr.label(allow_single_file = True),
+ "_builder": attr.label(
+ default = "//sphinxdocs/private:inventory_builder",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+)
diff --git a/sphinxdocs/private/sphinx_build.py b/sphinxdocs/private/sphinx_build.py
new file mode 100644
index 0000000..3b7b32e
--- /dev/null
+++ b/sphinxdocs/private/sphinx_build.py
@@ -0,0 +1,8 @@
+import os
+import pathlib
+import sys
+
+from sphinx.cmd.build import main
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/sphinxdocs/private/sphinx_server.py b/sphinxdocs/private/sphinx_server.py
new file mode 100644
index 0000000..e71889a
--- /dev/null
+++ b/sphinxdocs/private/sphinx_server.py
@@ -0,0 +1,49 @@
+import contextlib
+import errno
+import os
+import sys
+from http import server
+
+
+def main(argv):
+ build_workspace_directory = os.environ["BUILD_WORKSPACE_DIRECTORY"]
+ docs_directory = argv[1]
+ serve_directory = os.path.join(build_workspace_directory, docs_directory)
+
+ class DirectoryHandler(server.SimpleHTTPRequestHandler):
+ def __init__(self, *args, **kwargs):
+ super().__init__(directory=serve_directory, *args, **kwargs)
+
+ address = ("0.0.0.0", 8000)
+ # with server.ThreadingHTTPServer(address, DirectoryHandler) as (ip, port, httpd):
+ with _start_server(DirectoryHandler, "0.0.0.0", 8000) as (ip, port, httpd):
+ print(f"Serving...")
+ print(f" Address: http://{ip}:{port}")
+ print(f" Serving directory: {serve_directory}")
+ print(f" CWD: {os.getcwd()}")
+ print()
+ print("*** You do not need to restart this server to see changes ***")
+ print()
+ try:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+
+@contextlib.contextmanager
+def _start_server(handler, ip, start_port):
+ for port in range(start_port, start_port + 10):
+ try:
+ with server.ThreadingHTTPServer((ip, port), handler) as httpd:
+ yield ip, port, httpd
+ except OSError as e:
+ if e.errno == errno.EADDRINUSE:
+ pass
+ else:
+ raise
+ raise ValueError("Unable to find an available port")
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
diff --git a/sphinxdocs/private/sphinx_stardoc.bzl b/sphinxdocs/private/sphinx_stardoc.bzl
new file mode 100644
index 0000000..810dca3
--- /dev/null
+++ b/sphinxdocs/private/sphinx_stardoc.bzl
@@ -0,0 +1,139 @@
+# 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.
+
+"""Rules to generate Sphinx-compatible documentation for bzl files."""
+
+load("@bazel_skylib//lib:types.bzl", "types")
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+load("//python/private:util.bzl", "add_tag", "copy_propagating_kwargs") # buildifier: disable=bzl-visibility
+
+def sphinx_stardocs(name, docs, footer = None, **kwargs):
+ """Generate Sphinx-friendly Markdown docs using Stardoc for bzl libraries.
+
+ A `build_test` for the docs is also generated to ensure Stardoc is able
+ to process the files.
+
+ NOTE: This generates MyST-flavored Markdown.
+
+ Args:
+ name: `str`, the name of the resulting file group with the generated docs.
+ docs: `dict[str output, source]` of the bzl files to generate documentation
+ for. The `output` key is the path of the output filename, e.g.,
+ `foo/bar.md`. The `source` values can be either of:
+ * A `str` label that points to a `bzl_library` target. The target
+ name will replace `_bzl` with `.bzl` and use that as the input
+ bzl file to generate docs for. The target itself provides the
+ necessary dependencies.
+ * A `dict` with keys `input` and `dep`. The `input` key is a string
+ label to the bzl file to generate docs for. The `dep` key is a
+ string label to a `bzl_library` providing the necessary dependencies.
+ footer: optional [`label`] File to append to generated docs.
+ **kwargs: Additional kwargs to pass onto each `sphinx_stardoc` target
+ """
+ add_tag(kwargs, "@rules_python//sphinxdocs:sphinx_stardocs")
+ common_kwargs = copy_propagating_kwargs(kwargs)
+
+ stardocs = []
+ for out_name, entry in docs.items():
+ stardoc_kwargs = {}
+ stardoc_kwargs.update(kwargs)
+
+ if types.is_string(entry):
+ stardoc_kwargs["deps"] = [entry]
+ stardoc_kwargs["input"] = entry.replace("_bzl", ".bzl")
+ else:
+ stardoc_kwargs.update(entry)
+ stardoc_kwargs["deps"] = [stardoc_kwargs.pop("dep")]
+
+ doc_name = "_{}_{}".format(name.lstrip("_"), out_name.replace("/", "_"))
+ _sphinx_stardoc(
+ name = doc_name,
+ footer = footer,
+ out = out_name,
+ **stardoc_kwargs
+ )
+ stardocs.append(doc_name)
+
+ native.filegroup(
+ name = name,
+ srcs = stardocs,
+ **common_kwargs
+ )
+ build_test(
+ name = name + "_build_test",
+ targets = stardocs,
+ **common_kwargs
+ )
+
+def _sphinx_stardoc(*, name, out, footer = None, public_load_path = None, **kwargs):
+ stardoc_name = "_{}_stardoc".format(name.lstrip("_"))
+ stardoc_pb = stardoc_name + ".binaryproto"
+
+ if not public_load_path:
+ public_load_path = str(kwargs["input"])
+
+ stardoc(
+ name = stardoc_name,
+ out = stardoc_pb,
+ format = "proto",
+ **kwargs
+ )
+
+ _stardoc_proto_to_markdown(
+ name = name,
+ src = stardoc_pb,
+ output = out,
+ footer = footer,
+ public_load_path = public_load_path,
+ )
+
+def _stardoc_proto_to_markdown_impl(ctx):
+ args = ctx.actions.args()
+ args.use_param_file("@%s")
+ args.set_param_file_format("multiline")
+
+ inputs = [ctx.file.src]
+ args.add("--proto", ctx.file.src)
+ args.add("--output", ctx.outputs.output)
+
+ if ctx.file.footer:
+ args.add("--footer", ctx.file.footer)
+ inputs.append(ctx.file.footer)
+ if ctx.attr.public_load_path:
+ args.add("--public-load-path={}".format(ctx.attr.public_load_path))
+
+ ctx.actions.run(
+ executable = ctx.executable._proto_to_markdown,
+ arguments = [args],
+ inputs = inputs,
+ outputs = [ctx.outputs.output],
+ mnemonic = "SphinxStardocProtoToMd",
+ progress_message = "SphinxStardoc: converting proto to markdown: %{input} -> %{output}",
+ )
+
+_stardoc_proto_to_markdown = rule(
+ implementation = _stardoc_proto_to_markdown_impl,
+ attrs = {
+ "footer": attr.label(allow_single_file = True),
+ "output": attr.output(mandatory = True),
+ "public_load_path": attr.string(),
+ "src": attr.label(allow_single_file = True, mandatory = True),
+ "_proto_to_markdown": attr.label(
+ default = "//sphinxdocs/private:proto_to_markdown",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+)
diff --git a/tools/build_defs/python/tests/BUILD.bazel b/sphinxdocs/readthedocs.bzl
index e271850..4dfaf26 100644
--- a/tools/build_defs/python/tests/BUILD.bazel
+++ b/sphinxdocs/readthedocs.bzl
@@ -11,17 +11,8 @@
# 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.
+"""Starlark rules for integrating Sphinx and Readthedocs."""
-platform(
- name = "mac",
- constraint_values = [
- "@platforms//os:macos",
- ],
-)
+load("//sphinxdocs/private:readthedocs.bzl", _readthedocs_install = "readthedocs_install")
-platform(
- name = "linux",
- constraint_values = [
- "@platforms//os:linux",
- ],
-)
+readthedocs_install = _readthedocs_install
diff --git a/sphinxdocs/sphinx.bzl b/sphinxdocs/sphinx.bzl
new file mode 100644
index 0000000..a0b1a05
--- /dev/null
+++ b/sphinxdocs/sphinx.bzl
@@ -0,0 +1,37 @@
+# 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.
+
+"""# Rules to generate Sphinx documentation.
+
+The general usage of the Sphinx rules requires two pieces:
+
+1. Using `sphinx_docs` to define the docs to build and options for building.
+2. Defining a `sphinx-build` binary to run Sphinx with the necessary
+ dependencies to be used by (1); the `sphinx_build_binary` rule helps with
+ this.
+
+Defining your own `sphinx-build` binary is necessary because Sphinx uses
+a plugin model to support extensibility.
+"""
+
+load(
+ "//sphinxdocs/private:sphinx.bzl",
+ _sphinx_build_binary = "sphinx_build_binary",
+ _sphinx_docs = "sphinx_docs",
+ _sphinx_inventory = "sphinx_inventory",
+)
+
+sphinx_build_binary = _sphinx_build_binary
+sphinx_docs = _sphinx_docs
+sphinx_inventory = _sphinx_inventory
diff --git a/examples/pip_install/test.py b/sphinxdocs/sphinx_stardoc.bzl
index 0f5b7c9..623bc64 100644
--- a/examples/pip_install/test.py
+++ b/sphinxdocs/sphinx_stardoc.bzl
@@ -12,15 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import unittest
+"""Rules to generate Sphinx-compatible documentation for bzl files."""
-import main
+load("//sphinxdocs/private:sphinx_stardoc.bzl", _sphinx_stardocs = "sphinx_stardocs")
-
-class ExampleTest(unittest.TestCase):
- def test_main(self):
- self.assertIn("set_stream_logger", main.the_dir())
-
-
-if __name__ == "__main__":
- unittest.main()
+sphinx_stardocs = _sphinx_stardocs
diff --git a/python/pip_install/tools/lib/__init__.py b/sphinxdocs/tests/BUILD.bazel
index bbdfb4c..4101095 100644
--- a/python/pip_install/tools/lib/__init__.py
+++ b/sphinxdocs/tests/BUILD.bazel
@@ -11,4 +11,3 @@
# 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.
-
diff --git a/sphinxdocs/tests/proto_to_markdown/BUILD.bazel b/sphinxdocs/tests/proto_to_markdown/BUILD.bazel
new file mode 100644
index 0000000..2964785
--- /dev/null
+++ b/sphinxdocs/tests/proto_to_markdown/BUILD.bazel
@@ -0,0 +1,24 @@
+# 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.
+
+load("//python:py_test.bzl", "py_test")
+
+py_test(
+ name = "proto_to_markdown_test",
+ srcs = ["proto_to_markdown_test.py"],
+ deps = [
+ "//sphinxdocs/private:proto_to_markdown_lib",
+ "@dev_pip//absl_py",
+ ],
+)
diff --git a/sphinxdocs/tests/proto_to_markdown/proto_to_markdown_test.py b/sphinxdocs/tests/proto_to_markdown/proto_to_markdown_test.py
new file mode 100644
index 0000000..2f5b22e
--- /dev/null
+++ b/sphinxdocs/tests/proto_to_markdown/proto_to_markdown_test.py
@@ -0,0 +1,203 @@
+# 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 io
+import re
+
+from absl.testing import absltest
+from google.protobuf import text_format
+from stardoc.proto import stardoc_output_pb2
+
+from sphinxdocs.private import proto_to_markdown
+
+_EVERYTHING_MODULE = """\
+module_docstring: "MODULE_DOC_STRING"
+file: "@repo//pkg:foo.bzl"
+
+rule_info: {
+ rule_name: "rule_1"
+ doc_string: "RULE_1_DOC_STRING"
+ attribute: {
+ name: "rule_1_attr_1",
+ doc_string: "RULE_1_ATTR_1_DOC_STRING"
+ type: STRING
+ default_value: "RULE_1_ATTR_1_DEFAULT_VALUE"
+ }
+}
+provider_info: {
+ provider_name: "ProviderAlpha"
+ doc_string: "PROVIDER_ALPHA_DOC_STRING"
+ field_info: {
+ name: "ProviderAlpha_field_a"
+ doc_string: "PROVIDER_ALPHA_FIELD_A_DOC_STRING"
+ }
+}
+func_info: {
+ function_name: "function_1"
+ doc_string: "FUNCTION_1_DOC_STRING"
+ parameter: {
+ name: "function_1_param_a"
+ doc_string: "FUNCTION_1_PARAM_A_DOC_STRING"
+ default_value: "FUNCTION_1_PARAM_A_DEFAULT_VALUE"
+ }
+ return: {
+ doc_string: "FUNCTION_1_RETURN_DOC_STRING"
+ }
+ deprecated: {
+ doc_string: "FUNCTION_1_DEPRECATED_DOC_STRING"
+ }
+}
+aspect_info: {
+ aspect_name: "aspect_1"
+ doc_string: "ASPECT_1_DOC_STRING"
+ aspect_attribute: "aspect_1_aspect_attribute_a"
+ attribute: {
+ name: "aspect_1_attribute_a",
+ doc_string: "ASPECT_1_ATTRIBUTE_A_DOC_STRING"
+ type: INT
+ default_value: "694638"
+ }
+}
+module_extension_info: {
+ extension_name: "bzlmod_ext"
+ doc_string: "BZLMOD_EXT_DOC_STRING"
+ tag_class: {
+ tag_name: "bzlmod_ext_tag_a"
+ doc_string: "BZLMOD_EXT_TAG_A_DOC_STRING"
+ attribute: {
+ name: "bzlmod_ext_tag_a_attribute_1",
+ doc_string: "BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DOC_STRING"
+ type: STRING_LIST
+ default_value: "[BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DEFAULT_VALUE]"
+ }
+ }
+}
+repository_rule_info: {
+ rule_name: "repository_rule",
+ doc_string: "REPOSITORY_RULE_DOC_STRING"
+ attribute: {
+ name: "repository_rule_attribute_a",
+ doc_string: "REPOSITORY_RULE_ATTRIBUTE_A_DOC_STRING"
+ type: BOOLEAN
+ default_value: "True"
+ }
+ environ: "ENV_VAR_A"
+}
+"""
+
+
+class ProtoToMarkdownTest(absltest.TestCase):
+ def setUp(self):
+ super().setUp()
+ self.stream = io.StringIO()
+
+ def _render(self, module_text):
+ renderer = proto_to_markdown._MySTRenderer(
+ module=text_format.Parse(module_text, stardoc_output_pb2.ModuleInfo()),
+ out_stream=self.stream,
+ public_load_path="",
+ )
+ renderer.render()
+ return self.stream.getvalue()
+
+ def test_basic_rendering_everything(self):
+ actual = self._render(_EVERYTHING_MODULE)
+
+ self.assertRegex(actual, "# //pkg:foo.bzl")
+ self.assertRegex(actual, "MODULE_DOC_STRING")
+
+ self.assertRegex(actual, "## rule_1.*")
+ self.assertRegex(actual, "RULE_1_DOC_STRING")
+ self.assertRegex(actual, "rule_1_attr_1")
+ self.assertRegex(actual, "RULE_1_ATTR_1_DOC_STRING")
+ self.assertRegex(actual, "RULE_1_ATTR_1_DEFAULT_VALUE")
+
+ self.assertRegex(actual, "## ProviderAlpha")
+ self.assertRegex(actual, "PROVIDER_ALPHA_DOC_STRING")
+ self.assertRegex(actual, "ProviderAlpha_field_a")
+ self.assertRegex(actual, "PROVIDER_ALPHA_FIELD_A_DOC_STRING")
+
+ self.assertRegex(actual, "## function_1")
+ self.assertRegex(actual, "FUNCTION_1_DOC_STRING")
+ self.assertRegex(actual, "function_1_param_a")
+ self.assertRegex(actual, "FUNCTION_1_PARAM_A_DOC_STRING")
+ self.assertRegex(actual, "FUNCTION_1_PARAM_A_DEFAULT_VALUE")
+ self.assertRegex(actual, "FUNCTION_1_RETURN_DOC_STRING")
+ self.assertRegex(actual, "FUNCTION_1_DEPRECATED_DOC_STRING")
+
+ self.assertRegex(actual, "## aspect_1")
+ self.assertRegex(actual, "ASPECT_1_DOC_STRING")
+ self.assertRegex(actual, "aspect_1_aspect_attribute_a")
+ self.assertRegex(actual, "aspect_1_attribute_a")
+ self.assertRegex(actual, "ASPECT_1_ATTRIBUTE_A_DOC_STRING")
+ self.assertRegex(actual, "694638")
+
+ self.assertRegex(actual, "## bzlmod_ext")
+ self.assertRegex(actual, "BZLMOD_EXT_DOC_STRING")
+ self.assertRegex(actual, "### bzlmod_ext.bzlmod_ext_tag_a")
+ self.assertRegex(actual, "BZLMOD_EXT_TAG_A_DOC_STRING")
+ self.assertRegex(actual, "bzlmod_ext_tag_a_attribute_1")
+ self.assertRegex(actual, "BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DOC_STRING")
+ self.assertRegex(actual, "BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DEFAULT_VALUE")
+
+ self.assertRegex(actual, "## repository_rule")
+ self.assertRegex(actual, "REPOSITORY_RULE_DOC_STRING")
+ self.assertRegex(actual, "repository_rule_attribute_a")
+ self.assertRegex(actual, "REPOSITORY_RULE_ATTRIBUTE_A_DOC_STRING")
+ self.assertRegex(actual, "repository_rule_attribute_a.*=.*True")
+ self.assertRegex(actual, "ENV_VAR_A")
+
+ def test_render_signature(self):
+ actual = self._render(
+ """\
+file: "@repo//pkg:foo.bzl"
+func_info: {
+ function_name: "func"
+ parameter: {
+ name: "param_with_default"
+ default_value: "DEFAULT"
+ }
+ parameter: {
+ name: "param_without_default"
+ }
+ parameter: {
+ name: "last_param"
+ }
+}
+ """
+ )
+ self.assertIn("[param_with_default](#func_param_with_default)=DEFAULT,", actual)
+ self.assertIn("[param_without_default](#func_param_without_default),", actual)
+
+ def test_render_field_list(self):
+ actual = self._render(
+ """\
+file: "@repo//pkg:foo.bzl"
+func_info: {
+ function_name: "func"
+ parameter: {
+ name: "param"
+ default_value: "DEFAULT"
+ }
+}
+"""
+ )
+ self.assertRegex(
+ actual, re.compile("^:.*param.*¶.*headerlink.*:\n", re.MULTILINE)
+ )
+ self.assertRegex(actual, re.compile("^ .*#func_param", re.MULTILINE))
+
+
+if __name__ == "__main__":
+ absltest.main()
diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel
index 2dd2282..e7dbef6 100644
--- a/tests/BUILD.bazel
+++ b/tests/BUILD.bazel
@@ -1,17 +1,9 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
-load("//tools/bazel_integration_test:bazel_integration_test.bzl", "bazel_integration_test")
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
-bazel_integration_test(
- name = "pip_repository_entry_points_example",
- timeout = "long",
- # The dependencies needed for this test are not cross-platform: https://github.com/bazelbuild/rules_python/issues/260
- tags = ["fix-windows"],
-)
-
build_test(
name = "bzl_libraries_build_test",
targets = [
@@ -30,5 +22,6 @@ build_test(
"//python:py_test_bzl",
"//python/cc:py_cc_toolchain_bzl",
"//python/cc:py_cc_toolchain_info_bzl",
+ "//python/entry_points:py_console_script_binary_bzl",
],
)
diff --git a/tests/base_rules/BUILD.bazel b/tests/base_rules/BUILD.bazel
new file mode 100644
index 0000000..aa21042
--- /dev/null
+++ b/tests/base_rules/BUILD.bazel
@@ -0,0 +1,13 @@
+# 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.
diff --git a/tools/build_defs/python/tests/base_tests.bzl b/tests/base_rules/base_tests.bzl
index 467611f..fb95c15 100644
--- a/tools/build_defs/python/tests/base_tests.bzl
+++ b/tests/base_rules/base_tests.bzl
@@ -17,43 +17,99 @@ load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
load("@rules_testing//lib:truth.bzl", "matching")
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")
+load("//python/private:reexports.bzl", "BuiltinPyInfo") # buildifier: disable=bzl-visibility
+load("//tests/base_rules:py_info_subject.bzl", "py_info_subject")
+load("//tests/base_rules:util.bzl", pt_util = "util")
_tests = []
+_PRODUCES_PY_INFO_ATTRS = {
+ "imports": attr.string_list(),
+ "srcs": attr.label_list(allow_files = True),
+}
+
+def _create_py_info(ctx, provider_type):
+ return [provider_type(
+ transitive_sources = depset(ctx.files.srcs),
+ imports = depset(ctx.attr.imports),
+ )]
+
+def _produces_builtin_py_info_impl(ctx):
+ return _create_py_info(ctx, BuiltinPyInfo)
+
+_produces_builtin_py_info = rule(
+ implementation = _produces_builtin_py_info_impl,
+ attrs = _PRODUCES_PY_INFO_ATTRS,
+)
+
def _produces_py_info_impl(ctx):
- return [PyInfo(transitive_sources = depset(ctx.files.srcs))]
+ return _create_py_info(ctx, BuiltinPyInfo)
_produces_py_info = rule(
implementation = _produces_py_info_impl,
- attrs = {"srcs": attr.label_list(allow_files = True)},
+ attrs = _PRODUCES_PY_INFO_ATTRS,
)
-def _test_consumes_provider(name, config):
+def _not_produces_py_info_impl(ctx):
+ _ = ctx # @unused
+ return [DefaultInfo()]
+
+_not_produces_py_info = rule(
+ implementation = _not_produces_py_info_impl,
+)
+
+def _py_info_propagation_setup(name, config, produce_py_info_rule, test_impl):
rt_util.helper_target(
config.base_test_rule,
name = name + "_subject",
- deps = [name + "_produces_py_info"],
+ deps = [name + "_produces_builtin_py_info"],
)
rt_util.helper_target(
- _produces_py_info,
- name = name + "_produces_py_info",
+ produce_py_info_rule,
+ name = name + "_produces_builtin_py_info",
srcs = [rt_util.empty_file(name + "_produce.py")],
+ imports = ["custom-import"],
)
analysis_test(
name = name,
target = name + "_subject",
- impl = _test_consumes_provider_impl,
+ impl = test_impl,
)
-def _test_consumes_provider_impl(env, target):
- env.expect.that_target(target).provider(
- PyInfo,
+def _py_info_propagation_test_impl(env, target, provider_type):
+ info = env.expect.that_target(target).provider(
+ provider_type,
factory = py_info_subject,
- ).transitive_sources().contains("{package}/{test_name}_produce.py")
+ )
+
+ info.transitive_sources().contains("{package}/{test_name}_produce.py")
+ info.imports().contains("custom-import")
+
+def _test_py_info_propagation_builtin(name, config):
+ _py_info_propagation_setup(
+ name,
+ config,
+ _produces_builtin_py_info,
+ _test_py_info_propagation_builtin_impl,
+ )
+
+def _test_py_info_propagation_builtin_impl(env, target):
+ _py_info_propagation_test_impl(env, target, BuiltinPyInfo)
+
+_tests.append(_test_py_info_propagation_builtin)
+
+def _test_py_info_propagation(name, config):
+ _py_info_propagation_setup(
+ name,
+ config,
+ _produces_py_info,
+ _test_py_info_propagation_impl,
+ )
+
+def _test_py_info_propagation_impl(env, target):
+ _py_info_propagation_test_impl(env, target, PyInfo)
-_tests.append(_test_consumes_provider)
+_tests.append(_test_py_info_propagation)
def _test_requires_provider(name, config):
rt_util.helper_target(
@@ -62,7 +118,7 @@ def _test_requires_provider(name, config):
deps = [name + "_nopyinfo"],
)
rt_util.helper_target(
- native.filegroup,
+ _not_produces_py_info,
name = name + "_nopyinfo",
)
analysis_test(
diff --git a/tools/build_defs/python/tests/py_binary/BUILD.bazel b/tests/base_rules/py_binary/BUILD.bazel
index 17a6690..17a6690 100644
--- a/tools/build_defs/python/tests/py_binary/BUILD.bazel
+++ b/tests/base_rules/py_binary/BUILD.bazel
diff --git a/tools/build_defs/python/tests/py_binary/py_binary_tests.bzl b/tests/base_rules/py_binary/py_binary_tests.bzl
index 8d32632..571955d 100644
--- a/tools/build_defs/python/tests/py_binary/py_binary_tests.bzl
+++ b/tests/base_rules/py_binary/py_binary_tests.bzl
@@ -15,7 +15,7 @@
load("//python:defs.bzl", "py_binary")
load(
- "//tools/build_defs/python/tests:py_executable_base_tests.bzl",
+ "//tests/base_rules:py_executable_base_tests.bzl",
"create_executable_tests",
)
diff --git a/tools/build_defs/python/tests/py_executable_base_tests.bzl b/tests/base_rules/py_executable_base_tests.bzl
index c66ea11..3960579 100644
--- a/tools/build_defs/python/tests/py_executable_base_tests.bzl
+++ b/tests/base_rules/py_executable_base_tests.bzl
@@ -13,14 +13,57 @@
# limitations under the License.
"""Tests common to py_binary and py_test (executable rules)."""
+load("@rules_python_internal//:rules_python_config.bzl", rp_config = "config")
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("//tools/build_defs/python/tests:base_tests.bzl", "create_base_tests")
-load("//tools/build_defs/python/tests:util.bzl", "WINDOWS_ATTR", pt_util = "util")
+load("//tests/base_rules:base_tests.bzl", "create_base_tests")
+load("//tests/base_rules:util.bzl", "WINDOWS_ATTR", pt_util = "util")
+load("//tests/support:test_platforms.bzl", "WINDOWS")
_tests = []
+def _test_basic_windows(name, config):
+ if rp_config.enable_pystar:
+ target_compatible_with = []
+ else:
+ target_compatible_with = ["@platforms//:incompatible"]
+ rt_util.helper_target(
+ config.rule,
+ name = name + "_subject",
+ srcs = ["main.py"],
+ main = "main.py",
+ )
+ analysis_test(
+ name = name,
+ impl = _test_basic_windows_impl,
+ target = name + "_subject",
+ config_settings = {
+ # NOTE: The default for this flag is based on the Bazel host OS, not
+ # the target platform. For windows, it defaults to true, so force
+ # it to that to match behavior when this test runs on other
+ # platforms.
+ "//command_line_option:build_python_zip": "true",
+ "//command_line_option:cpu": "windows_x86_64",
+ "//command_line_option:crosstool_top": Label("//tests/cc:cc_toolchain_suite"),
+ "//command_line_option:extra_toolchains": [str(Label("//tests/cc:all"))],
+ "//command_line_option:platforms": [WINDOWS],
+ },
+ attr_values = {"target_compatible_with": target_compatible_with},
+ )
+
+def _test_basic_windows_impl(env, target):
+ target = env.expect.that_target(target)
+ target.executable().path().contains(".exe")
+ target.runfiles().contains_predicate(matching.str_endswith(
+ target.meta.format_str("/{name}.zip"),
+ ))
+ target.runfiles().contains_predicate(matching.str_endswith(
+ target.meta.format_str("/{name}.exe"),
+ ))
+
+_tests.append(_test_basic_windows)
+
def _test_executable_in_runfiles(name, config):
rt_util.helper_target(
config.rule,
diff --git a/tools/build_defs/python/tests/py_info_subject.bzl b/tests/base_rules/py_info_subject.bzl
index 20185e5..b23308c 100644
--- a/tools/build_defs/python/tests/py_info_subject.bzl
+++ b/tests/base_rules/py_info_subject.bzl
@@ -70,7 +70,7 @@ def _py_info_subject_imports(self):
Method: PyInfoSubject.imports
"""
return subjects.collection(
- self.actual.imports,
+ self.actual.imports.to_list(),
meta = self.meta.derive("imports()"),
)
diff --git a/tools/build_defs/python/tests/py_library/BUILD.bazel b/tests/base_rules/py_library/BUILD.bazel
index 9de414b..9de414b 100644
--- a/tools/build_defs/python/tests/py_library/BUILD.bazel
+++ b/tests/base_rules/py_library/BUILD.bazel
diff --git a/tools/build_defs/python/tests/py_library/py_library_tests.bzl b/tests/base_rules/py_library/py_library_tests.bzl
index 1fcb0c1..526735a 100644
--- a/tools/build_defs/python/tests/py_library/py_library_tests.bzl
+++ b/tests/base_rules/py_library/py_library_tests.bzl
@@ -4,8 +4,8 @@ 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("//python:defs.bzl", "PyRuntimeInfo", "py_library")
-load("//tools/build_defs/python/tests:base_tests.bzl", "create_base_tests")
-load("//tools/build_defs/python/tests:util.bzl", pt_util = "util")
+load("//tests/base_rules:base_tests.bzl", "create_base_tests")
+load("//tests/base_rules:util.bzl", pt_util = "util")
_tests = []
diff --git a/tools/build_defs/python/tests/py_test/BUILD.bazel b/tests/base_rules/py_test/BUILD.bazel
index 2dc0e5b..2dc0e5b 100644
--- a/tools/build_defs/python/tests/py_test/BUILD.bazel
+++ b/tests/base_rules/py_test/BUILD.bazel
diff --git a/tools/build_defs/python/tests/py_test/py_test_tests.bzl b/tests/base_rules/py_test/py_test_tests.bzl
index 1ecb252..f4b704e 100644
--- a/tools/build_defs/python/tests/py_test/py_test_tests.bzl
+++ b/tests/base_rules/py_test/py_test_tests.bzl
@@ -17,17 +17,16 @@ load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
load("@rules_testing//lib:util.bzl", rt_util = "util")
load("//python:defs.bzl", "py_test")
load(
- "//tools/build_defs/python/tests:py_executable_base_tests.bzl",
+ "//tests/base_rules:py_executable_base_tests.bzl",
"create_executable_tests",
)
-load("//tools/build_defs/python/tests:util.bzl", pt_util = "util")
+load("//tests/base_rules:util.bzl", pt_util = "util")
+load("//tests/support:test_platforms.bzl", "LINUX", "MAC")
-# Explicit Label() calls are required so that it resolves in @rules_python context instead of
-# @rules_testing context.
+# Explicit Label() calls are required so that it resolves in @rules_python
+# context instead of @rules_testing context.
_FAKE_CC_TOOLCHAIN = Label("//tests/cc:cc_toolchain_suite")
_FAKE_CC_TOOLCHAINS = [str(Label("//tests/cc:all"))]
-_PLATFORM_MAC = Label("//tools/build_defs/python/tests:mac")
-_PLATFORM_LINUX = Label("//tools/build_defs/python/tests:linux")
_tests = []
@@ -53,7 +52,7 @@ def _test_mac_requires_darwin_for_execution(name, config):
"//command_line_option:cpu": "darwin_x86_64",
"//command_line_option:crosstool_top": _FAKE_CC_TOOLCHAIN,
"//command_line_option:extra_toolchains": _FAKE_CC_TOOLCHAINS,
- "//command_line_option:platforms": [_PLATFORM_MAC],
+ "//command_line_option:platforms": [MAC],
},
)
@@ -85,7 +84,7 @@ def _test_non_mac_doesnt_require_darwin_for_execution(name, config):
"//command_line_option:cpu": "k8",
"//command_line_option:crosstool_top": _FAKE_CC_TOOLCHAIN,
"//command_line_option:extra_toolchains": _FAKE_CC_TOOLCHAINS,
- "//command_line_option:platforms": [_PLATFORM_LINUX],
+ "//command_line_option:platforms": [LINUX],
},
)
diff --git a/tools/build_defs/python/tests/util.bzl b/tests/base_rules/util.bzl
index 9b386ca..a02cafa 100644
--- a/tools/build_defs/python/tests/util.bzl
+++ b/tests/base_rules/util.bzl
@@ -14,6 +14,7 @@
"""Helpers and utilities multiple tests re-use."""
load("@bazel_skylib//lib:structs.bzl", "structs")
+load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER") # buildifier: disable=bzl-visibility
# Use this with is_windows()
WINDOWS_ATTR = {"windows": attr.label(default = "@platforms//os:windows")}
@@ -53,9 +54,7 @@ def _struct_with(s, **kwargs):
return struct(**struct_dict)
def _is_bazel_6_or_higher():
- # Bazel 5.4 has a bug where every access of testing.ExecutionInfo is a
- # different object that isn't equal to any other. This is fixed in bazel 6+.
- return testing.ExecutionInfo == testing.ExecutionInfo
+ return IS_BAZEL_6_OR_HIGHER
def _is_windows(env):
"""Tell if the target platform is windows.
diff --git a/tests/cc/BUILD.bazel b/tests/cc/BUILD.bazel
index 876d163..ef64d6d 100644
--- a/tests/cc/BUILD.bazel
+++ b/tests/cc/BUILD.bazel
@@ -19,6 +19,8 @@ load(":fake_cc_toolchain_config.bzl", "fake_cc_toolchain_config")
package(default_visibility = ["//:__subpackages__"])
+exports_files(["fake_header.h"])
+
toolchain(
name = "fake_py_cc_toolchain",
tags = PREVENT_IMPLICIT_BUILDING_TAGS,
@@ -48,6 +50,7 @@ cc_toolchain_suite(
toolchains = {
"darwin_x86_64": ":mac_toolchain",
"k8": ":linux_toolchain",
+ "windows_x86_64": ":windows_toolchain",
},
)
@@ -104,3 +107,29 @@ fake_cc_toolchain_config(
target_cpu = "k8",
toolchain_identifier = "linux-toolchain",
)
+
+cc_toolchain(
+ name = "windows_toolchain",
+ all_files = ":empty",
+ compiler_files = ":empty",
+ dwp_files = ":empty",
+ linker_files = ":empty",
+ objcopy_files = ":empty",
+ strip_files = ":empty",
+ supports_param_files = 0,
+ toolchain_config = ":windows_toolchain_config",
+ toolchain_identifier = "windows-toolchain",
+)
+
+toolchain(
+ name = "windows_toolchain_definition",
+ target_compatible_with = ["@platforms//os:windows"],
+ toolchain = ":windows_toolchain",
+ toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+fake_cc_toolchain_config(
+ name = "windows_toolchain_config",
+ target_cpu = "windows_x86_64",
+ toolchain_identifier = "windows-toolchain",
+)
diff --git a/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl b/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl
index 2b8b2ee..931a9c1 100644
--- a/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl
+++ b/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl
@@ -62,6 +62,18 @@ def _test_current_toolchain_headers_impl(env, target):
_tests.append(_test_current_toolchain_headers)
+def _test_toolchain_is_registered_by_default(name):
+ analysis_test(
+ name = name,
+ impl = _test_toolchain_is_registered_by_default_impl,
+ target = "//python/cc:current_py_cc_headers",
+ )
+
+def _test_toolchain_is_registered_by_default_impl(env, target):
+ env.expect.that_target(target).has_provider(CcInfo)
+
+_tests.append(_test_toolchain_is_registered_by_default)
+
def current_py_cc_headers_test_suite(name):
test_suite(
name = name,
diff --git a/tests/config_settings/transition/BUILD.bazel b/tests/config_settings/transition/BUILD.bazel
index 21fa50e..19d4958 100644
--- a/tests/config_settings/transition/BUILD.bazel
+++ b/tests/config_settings/transition/BUILD.bazel
@@ -1,3 +1,6 @@
+load(":multi_version_tests.bzl", "multi_version_test_suite")
load(":py_args_tests.bzl", "py_args_test_suite")
py_args_test_suite(name = "py_args_tests")
+
+multi_version_test_suite(name = "multi_version_tests")
diff --git a/tests/config_settings/transition/multi_version_tests.bzl b/tests/config_settings/transition/multi_version_tests.bzl
new file mode 100644
index 0000000..32f7209
--- /dev/null
+++ b/tests/config_settings/transition/multi_version_tests.bzl
@@ -0,0 +1,68 @@
+# 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.
+"""Tests for py_test."""
+
+load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("@rules_testing//lib:util.bzl", rt_util = "util")
+load("//python:versions.bzl", "TOOL_VERSIONS")
+load("//python/config_settings:transition.bzl", py_binary_transitioned = "py_binary", py_test_transitioned = "py_test")
+
+_tests = []
+
+def _test_py_test_with_transition(name):
+ rt_util.helper_target(
+ py_test_transitioned,
+ name = name + "_subject",
+ srcs = [name + "_subject.py"],
+ python_version = TOOL_VERSIONS.keys()[0],
+ )
+
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_py_test_with_transition_impl,
+ )
+
+def _test_py_test_with_transition_impl(env, target):
+ # Nothing to assert; we just want to make sure it builds
+ _ = env, target # @unused
+
+_tests.append(_test_py_test_with_transition)
+
+def _test_py_binary_with_transition(name):
+ rt_util.helper_target(
+ py_binary_transitioned,
+ name = name + "_subject",
+ srcs = [name + "_subject.py"],
+ python_version = TOOL_VERSIONS.keys()[0],
+ )
+
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_py_binary_with_transition_impl,
+ )
+
+def _test_py_binary_with_transition_impl(env, target):
+ # Nothing to assert; we just want to make sure it builds
+ _ = env, target # @unused
+
+_tests.append(_test_py_binary_with_transition)
+
+def multi_version_test_suite(name):
+ test_suite(
+ name = name,
+ tests = _tests,
+ )
diff --git a/tests/entry_points/BUILD.bazel b/tests/entry_points/BUILD.bazel
new file mode 100644
index 0000000..7a22d3c
--- /dev/null
+++ b/tests/entry_points/BUILD.bazel
@@ -0,0 +1,39 @@
+# 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.
+
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+load("//python:py_test.bzl", "py_test")
+load(":simple_macro.bzl", "py_console_script_binary_in_a_macro")
+
+py_test(
+ name = "py_console_script_gen_test",
+ srcs = ["py_console_script_gen_test.py"],
+ main = "py_console_script_gen_test.py",
+ visibility = ["//visibility:private"],
+ deps = [
+ "//python/private:py_console_script_gen_lib",
+ ],
+)
+
+py_console_script_binary_in_a_macro(
+ name = "twine",
+ pkg = "@publish_deps_twine//:pkg",
+)
+
+build_test(
+ name = "build_entry_point",
+ targets = [
+ ":twine",
+ ],
+)
diff --git a/tests/entry_points/py_console_script_gen_test.py b/tests/entry_points/py_console_script_gen_test.py
new file mode 100644
index 0000000..a5fceb6
--- /dev/null
+++ b/tests/entry_points/py_console_script_gen_test.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python3
+# 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 pathlib
+import tempfile
+import textwrap
+import unittest
+
+from python.private.py_console_script_gen import run
+
+
+class RunTest(unittest.TestCase):
+ def setUp(self):
+ self.maxDiff = None
+
+ def test_no_console_scripts_error(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ tmpdir = pathlib.Path(tmpdir)
+ outfile = tmpdir / "out.py"
+ given_contents = (
+ textwrap.dedent(
+ """
+ [non_console_scripts]
+ foo = foo.bar:fizz
+ """
+ ).strip()
+ + "\n"
+ )
+ entry_points = tmpdir / "entry_points.txt"
+ entry_points.write_text(given_contents)
+
+ with self.assertRaises(RuntimeError) as cm:
+ run(
+ entry_points=entry_points,
+ out=outfile,
+ console_script=None,
+ console_script_guess="",
+ )
+
+ self.assertEqual(
+ "The package does not provide any console_scripts in its entry_points.txt",
+ cm.exception.args[0],
+ )
+
+ def test_no_entry_point_selected_error(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ tmpdir = pathlib.Path(tmpdir)
+ outfile = tmpdir / "out.py"
+ given_contents = (
+ textwrap.dedent(
+ """
+ [console_scripts]
+ foo = foo.bar:fizz
+ """
+ ).strip()
+ + "\n"
+ )
+ entry_points = tmpdir / "entry_points.txt"
+ entry_points.write_text(given_contents)
+
+ with self.assertRaises(RuntimeError) as cm:
+ run(
+ entry_points=entry_points,
+ out=outfile,
+ console_script=None,
+ console_script_guess="bar-baz",
+ )
+
+ self.assertEqual(
+ "Tried to guess that you wanted 'bar-baz', but could not find it. Please select one of the following console scripts: foo",
+ cm.exception.args[0],
+ )
+
+ def test_incorrect_entry_point(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ tmpdir = pathlib.Path(tmpdir)
+ outfile = tmpdir / "out.py"
+ given_contents = (
+ textwrap.dedent(
+ """
+ [console_scripts]
+ foo = foo.bar:fizz
+ bar = foo.bar:buzz
+ """
+ ).strip()
+ + "\n"
+ )
+ entry_points = tmpdir / "entry_points.txt"
+ entry_points.write_text(given_contents)
+
+ with self.assertRaises(RuntimeError) as cm:
+ run(
+ entry_points=entry_points,
+ out=outfile,
+ console_script="baz",
+ console_script_guess="",
+ )
+
+ self.assertEqual(
+ "The console_script 'baz' was not found, only the following are available: bar, foo",
+ cm.exception.args[0],
+ )
+
+ def test_a_single_entry_point(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ tmpdir = pathlib.Path(tmpdir)
+ given_contents = (
+ textwrap.dedent(
+ """
+ [console_scripts]
+ foo = foo.bar:baz
+ """
+ ).strip()
+ + "\n"
+ )
+ entry_points = tmpdir / "entry_points.txt"
+ entry_points.write_text(given_contents)
+ out = tmpdir / "foo.py"
+
+ run(
+ entry_points=entry_points,
+ out=out,
+ console_script=None,
+ console_script_guess="foo",
+ )
+
+ got = out.read_text()
+
+ want = textwrap.dedent(
+ """\
+ import sys
+
+ # See @rules_python//python/private:py_console_script_gen.py for explanation
+ if getattr(sys.flags, "safe_path", False):
+ # We are running on Python 3.11 and we don't need this workaround
+ pass
+ elif ".runfiles" not in sys.path[0]:
+ sys.path = sys.path[1:]
+
+ try:
+ from foo.bar import baz
+ except ImportError:
+ entries = "\\n".join(sys.path)
+ print("Printing sys.path entries for easier debugging:", file=sys.stderr)
+ print(f"sys.path is:\\n{entries}", file=sys.stderr)
+ raise
+
+ if __name__ == "__main__":
+ sys.exit(baz())
+ """
+ )
+ self.assertEqual(want, got)
+
+ def test_a_second_entry_point_class_method(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ tmpdir = pathlib.Path(tmpdir)
+ given_contents = (
+ textwrap.dedent(
+ """
+ [console_scripts]
+ foo = foo.bar:Bar.baz
+ bar = foo.baz:Bar.baz
+ """
+ ).strip()
+ + "\n"
+ )
+ entry_points = tmpdir / "entry_points.txt"
+ entry_points.write_text(given_contents)
+ out = tmpdir / "out.py"
+
+ run(
+ entry_points=entry_points,
+ out=out,
+ console_script="bar",
+ console_script_guess="",
+ )
+
+ got = out.read_text()
+
+ self.assertRegex(got, "from foo\.baz import Bar")
+ self.assertRegex(got, "sys\.exit\(Bar\.baz\(\)\)")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/entry_points/simple_macro.bzl b/tests/entry_points/simple_macro.bzl
new file mode 100644
index 0000000..4764a3f
--- /dev/null
+++ b/tests/entry_points/simple_macro.bzl
@@ -0,0 +1,31 @@
+# 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.
+
+"""
+A simple test macro.
+"""
+
+load("//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
+
+def py_console_script_binary_in_a_macro(name, pkg):
+ """A simple macro to see that we can use our macro in a macro.
+
+ Args:
+ name, str: the name of the target
+ pkg, str: the pkg target
+ """
+ py_console_script_binary(
+ name = name,
+ pkg = Label(pkg),
+ )
diff --git a/tests/integration/BUILD.bazel b/tests/integration/BUILD.bazel
new file mode 100644
index 0000000..0e793cd
--- /dev/null
+++ b/tests/integration/BUILD.bazel
@@ -0,0 +1,103 @@
+# 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.
+
+load("@rules_bazel_integration_test//bazel_integration_test:defs.bzl", "default_test_runner")
+load(":integration_test.bzl", "rules_python_integration_test")
+
+licenses(["notice"])
+
+_WORKSPACE_FLAGS = [
+ "--noenable_bzlmod",
+]
+
+_WORKSPACE_GAZELLE_PLUGIN_FLAGS = [
+ "--override_repository=rules_python_gazelle_plugin=../../../rules_python_gazelle_plugin",
+]
+
+_GAZELLE_PLUGIN_FLAGS = [
+ "--override_module=rules_python_gazelle_plugin=../../../rules_python_gazelle_plugin",
+]
+
+default_test_runner(
+ name = "workspace_test_runner",
+ bazel_cmds = [
+ "info {}".format(" ".join(_WORKSPACE_FLAGS)),
+ "test {} //...".format(" ".join(_WORKSPACE_FLAGS)),
+ ],
+ visibility = ["//visibility:public"],
+)
+
+default_test_runner(
+ name = "workspace_test_runner_gazelle_plugin",
+ bazel_cmds = [
+ "info {}".format(" ".join(_WORKSPACE_FLAGS + _WORKSPACE_GAZELLE_PLUGIN_FLAGS)),
+ "test {} //...".format(" ".join(_WORKSPACE_FLAGS + _WORKSPACE_GAZELLE_PLUGIN_FLAGS)),
+ ],
+ visibility = ["//visibility:public"],
+)
+
+default_test_runner(
+ name = "test_runner",
+ visibility = ["//visibility:public"],
+)
+
+default_test_runner(
+ name = "test_runner_gazelle_plugin",
+ bazel_cmds = [
+ "info {}".format(" ".join(_GAZELLE_PLUGIN_FLAGS)),
+ "test {} //...".format(" ".join(_GAZELLE_PLUGIN_FLAGS)),
+ ],
+ visibility = ["//visibility:public"],
+)
+
+# TODO: add compile_pip_requirements_test_from_external_repo
+
+rules_python_integration_test(
+ name = "pip_repository_entry_points_workspace_test",
+ timeout = "long",
+ bzlmod = False,
+ # The dependencies needed for this test are not cross-platform: https://github.com/bazelbuild/rules_python/issues/260
+ tags = ["fix-windows"],
+ workspace_path = "pip_repository_entry_points",
+)
+
+rules_python_integration_test(
+ name = "compile_pip_requirements_test",
+)
+
+rules_python_integration_test(
+ name = "compile_pip_requirements_workspace_test",
+ bzlmod = False,
+ workspace_path = "compile_pip_requirements",
+)
+
+rules_python_integration_test(
+ name = "ignore_root_user_error_test",
+)
+
+rules_python_integration_test(
+ name = "ignore_root_user_error_workspace_test",
+ bzlmod = False,
+ workspace_path = "ignore_root_user_error",
+)
+
+rules_python_integration_test(
+ name = "py_cc_toolchain_registered_test",
+)
+
+rules_python_integration_test(
+ name = "py_cc_toolchain_registered_workspace_test",
+ bzlmod = False,
+ workspace_path = "py_cc_toolchain_registered",
+)
diff --git a/tests/integration/bazel_from_env b/tests/integration/bazel_from_env
new file mode 100755
index 0000000..96780b8
--- /dev/null
+++ b/tests/integration/bazel_from_env
@@ -0,0 +1,6 @@
+#!/bin/bash
+#
+# A simple wrapper so rules_bazel_integration_test can use the
+# bazel version inherited from the environment.
+
+bazel "$@"
diff --git a/tests/integration/compile_pip_requirements/.bazelignore b/tests/integration/compile_pip_requirements/.bazelignore
new file mode 100644
index 0000000..2261bd4
--- /dev/null
+++ b/tests/integration/compile_pip_requirements/.bazelignore
@@ -0,0 +1,4 @@
+# While normally ignored by default, it must be explicitly
+# specified so that compile_pip_requirements_test_from_external_workspace
+# properly ignores it
+bazel-compile_pip_requirements
diff --git a/tests/compile_pip_requirements/.bazelrc b/tests/integration/compile_pip_requirements/.bazelrc
index f23315a..f23315a 100644
--- a/tests/compile_pip_requirements/.bazelrc
+++ b/tests/integration/compile_pip_requirements/.bazelrc
diff --git a/tests/compile_pip_requirements/.gitignore b/tests/integration/compile_pip_requirements/.gitignore
index ac51a05..ac51a05 100644
--- a/tests/compile_pip_requirements/.gitignore
+++ b/tests/integration/compile_pip_requirements/.gitignore
diff --git a/tests/compile_pip_requirements/BUILD.bazel b/tests/integration/compile_pip_requirements/BUILD.bazel
index ad5ee1a..6df46b8 100644
--- a/tests/compile_pip_requirements/BUILD.bazel
+++ b/tests/integration/compile_pip_requirements/BUILD.bazel
@@ -21,30 +21,22 @@ EOF
compile_pip_requirements(
name = "requirements",
+ src = "requirements.txt",
data = [
"requirements.in",
"requirements_extra.in",
],
- extra_args = [
- "--allow-unsafe",
- "--resolver=backtracking",
- ],
- requirements_in = "requirements.txt",
requirements_txt = "requirements_lock.txt",
)
compile_pip_requirements(
name = "requirements_nohashes",
+ src = "requirements.txt",
data = [
"requirements.in",
"requirements_extra.in",
],
- extra_args = [
- "--allow-unsafe",
- "--resolver=backtracking",
- ],
generate_hashes = False,
- requirements_in = "requirements.txt",
requirements_txt = "requirements_nohashes_lock.txt",
)
@@ -63,16 +55,12 @@ EOF
compile_pip_requirements(
name = "os_specific_requirements",
+ src = "requirements_os_specific.in",
data = [
"requirements_extra.in",
"requirements_os_specific.in",
],
- extra_args = [
- "--allow-unsafe",
- "--resolver=backtracking",
- ],
requirements_darwin = "requirements_lock_darwin.txt",
- requirements_in = "requirements_os_specific.in",
requirements_linux = "requirements_lock_linux.txt",
requirements_txt = "requirements_lock.txt",
requirements_windows = "requirements_lock_windows.txt",
diff --git a/tests/integration/compile_pip_requirements/MODULE.bazel b/tests/integration/compile_pip_requirements/MODULE.bazel
new file mode 100644
index 0000000..a3f3d47
--- /dev/null
+++ b/tests/integration/compile_pip_requirements/MODULE.bazel
@@ -0,0 +1,12 @@
+module(name = "compile_pip_requirements")
+
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+ module_name = "rules_python",
+ path = "../../..",
+)
+
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+python.toolchain(
+ python_version = "3.9",
+)
diff --git a/tests/compile_pip_requirements/README.md b/tests/integration/compile_pip_requirements/README.md
index 3777624..3777624 100644
--- a/tests/compile_pip_requirements/README.md
+++ b/tests/integration/compile_pip_requirements/README.md
diff --git a/tests/compile_pip_requirements/WORKSPACE b/tests/integration/compile_pip_requirements/WORKSPACE
index d3a419c..5a2204b 100644
--- a/tests/compile_pip_requirements/WORKSPACE
+++ b/tests/integration/compile_pip_requirements/WORKSPACE
@@ -1,6 +1,6 @@
local_repository(
name = "rules_python",
- path = "../..",
+ path = "../../..",
)
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
diff --git a/tests/integration/compile_pip_requirements/WORKSPACE.bzlmod b/tests/integration/compile_pip_requirements/WORKSPACE.bzlmod
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/integration/compile_pip_requirements/WORKSPACE.bzlmod
diff --git a/tests/compile_pip_requirements/requirements.txt b/tests/integration/compile_pip_requirements/requirements.txt
index 4826399..4826399 100644
--- a/tests/compile_pip_requirements/requirements.txt
+++ b/tests/integration/compile_pip_requirements/requirements.txt
diff --git a/tests/compile_pip_requirements/requirements_lock.txt b/tests/integration/compile_pip_requirements/requirements_lock.txt
index 4ca4a11..5ce7d3b 100644
--- a/tests/compile_pip_requirements/requirements_lock.txt
+++ b/tests/integration/compile_pip_requirements/requirements_lock.txt
@@ -4,6 +4,8 @@
#
# bazel run //:requirements.update
#
+
+# The following packages are considered to be unsafe in a requirements file:
pip==22.3.1 \
--hash=sha256:65fd48317359f3af8e593943e6ae1506b66325085ea64b706a998c6e83eeaf38 \
--hash=sha256:908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077
diff --git a/tests/compile_pip_requirements/requirements_lock_darwin.txt b/tests/integration/compile_pip_requirements/requirements_lock_darwin.txt
index 7b580a2..0428dc0 100644
--- a/tests/compile_pip_requirements/requirements_lock_darwin.txt
+++ b/tests/integration/compile_pip_requirements/requirements_lock_darwin.txt
@@ -4,6 +4,8 @@
#
# bazel run //:os_specific_requirements.update
#
+
+# The following packages are considered to be unsafe in a requirements file:
pip==22.2.2 ; sys_platform == "darwin" \
--hash=sha256:3fd1929db052f056d7a998439176d3333fa1b3f6c1ad881de1885c0717608a4b \
--hash=sha256:b61a374b5bc40a6e982426aede40c9b5a08ff20e640f5b56977f4f91fed1e39a
diff --git a/tests/compile_pip_requirements/requirements_lock_linux.txt b/tests/integration/compile_pip_requirements/requirements_lock_linux.txt
index 54eca17..37c4d49 100644
--- a/tests/compile_pip_requirements/requirements_lock_linux.txt
+++ b/tests/integration/compile_pip_requirements/requirements_lock_linux.txt
@@ -4,6 +4,8 @@
#
# bazel run //:os_specific_requirements.update
#
+
+# The following packages are considered to be unsafe in a requirements file:
pip==22.3 ; sys_platform == "linux" \
--hash=sha256:1daab4b8d3b97d1d763caeb01a4640a2250a0ea899e257b1e44b9eded91e15ab \
--hash=sha256:8182aec21dad6c0a49a2a3d121a87cd524b950e0b6092b181625f07ebdde7530
diff --git a/tests/compile_pip_requirements/requirements_lock_windows.txt b/tests/integration/compile_pip_requirements/requirements_lock_windows.txt
index 5803d8e..5f8e0fa 100644
--- a/tests/compile_pip_requirements/requirements_lock_windows.txt
+++ b/tests/integration/compile_pip_requirements/requirements_lock_windows.txt
@@ -4,6 +4,8 @@
#
# bazel run //:os_specific_requirements.update
#
+
+# The following packages are considered to be unsafe in a requirements file:
pip==22.2.1 ; sys_platform == "win32" \
--hash=sha256:0bbbc87dfbe6eed217beff0021f8b7dea04c8f4a0baa9d31dc4cff281ffc5b2b \
--hash=sha256:50516e47a2b79e77446f0d05649f0d53772c192571486236b1905492bfc24bac
diff --git a/tests/compile_pip_requirements/requirements_nohashes_lock.txt b/tests/integration/compile_pip_requirements/requirements_nohashes_lock.txt
index 2b08a8e..f6f0d86 100644
--- a/tests/compile_pip_requirements/requirements_nohashes_lock.txt
+++ b/tests/integration/compile_pip_requirements/requirements_nohashes_lock.txt
@@ -4,6 +4,8 @@
#
# bazel run //:requirements_nohashes.update
#
+
+# The following packages are considered to be unsafe in a requirements file:
pip==22.3.1
# via -r requirements.in
setuptools==65.6.3
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/.bazelrc b/tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc
index b98fc09..b98fc09 100644
--- a/tests/compile_pip_requirements_test_from_external_workspace/.bazelrc
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/.gitignore b/tests/integration/compile_pip_requirements_test_from_external_repo/.gitignore
index ac51a05..ac51a05 100644
--- a/tests/compile_pip_requirements_test_from_external_workspace/.gitignore
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/.gitignore
diff --git a/tests/integration/compile_pip_requirements_test_from_external_repo/BUILD.bazel b/tests/integration/compile_pip_requirements_test_from_external_repo/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/BUILD.bazel
diff --git a/tests/integration/compile_pip_requirements_test_from_external_repo/MODULE.bazel b/tests/integration/compile_pip_requirements_test_from_external_repo/MODULE.bazel
new file mode 100644
index 0000000..596a0bc
--- /dev/null
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/MODULE.bazel
@@ -0,0 +1,25 @@
+module(name = "compile_pip_requirements_test_from_external_repo")
+
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+ module_name = "rules_python",
+ path = "../../..",
+)
+
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+python.toolchain(
+ python_version = "3.9",
+)
+
+bazel_dep(name = "compile_pip_requirements", version = "0.0.0")
+local_path_override(
+ module_name = "compile_pip_requirements",
+ path = "../compile_pip_requirements",
+)
+
+pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+pip.parse(
+ hub_name = "pypi",
+ python_version = "3.9",
+ requirements_lock = "@compile_pip_requirements//:requirements_lock.txt",
+)
diff --git a/tests/compile_pip_requirements_test_from_external_workspace/README.md b/tests/integration/compile_pip_requirements_test_from_external_repo/README.md
index 8ce77ca..e8fa032 100644
--- a/tests/compile_pip_requirements_test_from_external_workspace/README.md
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/README.md
@@ -1,3 +1,3 @@
-# compile_pip_requirements_test_from_external_workspace
+# compile_pip_requirements_test_from_external_repo
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/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE
index 35686a1..9a08c28 100644
--- a/tests/compile_pip_requirements_test_from_external_workspace/WORKSPACE
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE
@@ -1,6 +1,6 @@
local_repository(
name = "rules_python",
- path = "../..",
+ path = "../../..",
)
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
@@ -20,14 +20,14 @@ load("@python39//:defs.bzl", "interpreter")
load("@rules_python//python:pip.bzl", "pip_parse")
local_repository(
- name = "external_repository",
+ name = "compile_pip_requirements",
path = "../compile_pip_requirements",
)
pip_parse(
name = "pypi",
python_interpreter_target = interpreter,
- requirements_lock = "@external_repository//:requirements_lock.txt",
+ requirements_lock = "@compile_pip_requirements//:requirements_lock.txt",
)
load("@pypi//:requirements.bzl", "install_deps")
diff --git a/tests/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE.bzlmod b/tests/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE.bzlmod
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/integration/compile_pip_requirements_test_from_external_repo/WORKSPACE.bzlmod
diff --git a/tests/ignore_root_user_error/.bazelrc b/tests/integration/ignore_root_user_error/.bazelrc
index f23315a..f23315a 100644
--- a/tests/ignore_root_user_error/.bazelrc
+++ b/tests/integration/ignore_root_user_error/.bazelrc
diff --git a/tests/ignore_root_user_error/.gitignore b/tests/integration/ignore_root_user_error/.gitignore
index ac51a05..ac51a05 100644
--- a/tests/ignore_root_user_error/.gitignore
+++ b/tests/integration/ignore_root_user_error/.gitignore
diff --git a/tests/ignore_root_user_error/BUILD.bazel b/tests/integration/ignore_root_user_error/BUILD.bazel
index f907624..f907624 100644
--- a/tests/ignore_root_user_error/BUILD.bazel
+++ b/tests/integration/ignore_root_user_error/BUILD.bazel
diff --git a/tests/ignore_root_user_error/README.md b/tests/integration/ignore_root_user_error/README.md
index 47da5eb..47da5eb 100644
--- a/tests/ignore_root_user_error/README.md
+++ b/tests/integration/ignore_root_user_error/README.md
diff --git a/tests/ignore_root_user_error/WORKSPACE b/tests/integration/ignore_root_user_error/WORKSPACE
index e0528e4..c21b01e 100644
--- a/tests/ignore_root_user_error/WORKSPACE
+++ b/tests/integration/ignore_root_user_error/WORKSPACE
@@ -1,9 +1,11 @@
local_repository(
name = "rules_python",
- path = "../..",
+ path = "../../..",
)
-load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
+
+py_repositories()
python_register_toolchains(
name = "python39",
diff --git a/tests/ignore_root_user_error/foo_test.py b/tests/integration/ignore_root_user_error/foo_test.py
index 724cdcb..724cdcb 100644
--- a/tests/ignore_root_user_error/foo_test.py
+++ b/tests/integration/ignore_root_user_error/foo_test.py
diff --git a/tests/integration/integration_test.bzl b/tests/integration/integration_test.bzl
new file mode 100644
index 0000000..16d6a5a
--- /dev/null
+++ b/tests/integration/integration_test.bzl
@@ -0,0 +1,96 @@
+# 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.
+"""Helpers for running bazel-in-bazel integration tests."""
+
+load("@bazel_binaries//:defs.bzl", "bazel_binaries")
+load(
+ "@rules_bazel_integration_test//bazel_integration_test:defs.bzl",
+ "bazel_integration_tests",
+ "integration_test_utils",
+)
+
+def rules_python_integration_test(
+ name,
+ workspace_path = None,
+ bzlmod = True,
+ gazelle_plugin = False,
+ tags = None,
+ **kwargs):
+ """Runs a bazel-in-bazel integration test.
+
+ Args:
+ name: Name of the test. This gets appended by the bazel version.
+ workspace_path: The directory name. Defaults to `name` without the
+ `_test` suffix.
+ bzlmod: bool, default True. If true, run with bzlmod enabled, otherwise
+ disable bzlmod.
+ gazelle_plugin: Whether the test uses the gazelle plugin.
+ tags: Test tags.
+ **kwargs: Passed to the upstream `bazel_integration_tests` rule.
+ """
+ workspace_path = workspace_path or name.removesuffix("_test")
+ if bzlmod:
+ if gazelle_plugin:
+ test_runner = "//tests/integration:test_runner_gazelle_plugin"
+ else:
+ test_runner = "//tests/integration:test_runner"
+ elif gazelle_plugin:
+ test_runner = "//tests/integration:workspace_test_runner_gazelle_plugin"
+ else:
+ test_runner = "//tests/integration:workspace_test_runner"
+
+ # Because glob expansion happens at loading time, the bazel-* symlinks
+ # in the workspaces can recursively expand to tens-of-thousands of entries,
+ # which consumes lots of CPU and RAM and can render the system unusable.
+ # To help prevent that, cap the size of the glob expansion.
+ workspace_files = integration_test_utils.glob_workspace_files(workspace_path)
+ if len(workspace_files) > 1000:
+ fail("Workspace {} has too many files. This likely means a bazel-* " +
+ "symlink is being followed when it should be ignored.")
+
+ # bazel_integration_tests creates a separate file group target of the workspace
+ # files for each bazel version, even though the file groups are the same
+ # for each one.
+ # To avoid that, manually create a single filegroup once and re-use it.
+ native.filegroup(
+ name = name + "_workspace_files",
+ srcs = workspace_files + [
+ "//:distribution",
+ ],
+ )
+ kwargs.setdefault("size", "enormous")
+ bazel_integration_tests(
+ name = name,
+ workspace_path = workspace_path,
+ test_runner = test_runner,
+ bazel_versions = bazel_binaries.versions.all,
+ workspace_files = [name + "_workspace_files"],
+ # Override the tags so that the `manual` tag isn't applied.
+ tags = (tags or []) + [
+ # These tests are very heavy weight, so much so that only a couple
+ # can be run in parallel without harming their reliability,
+ # overall runtime, and the system's stability. Unfortunately,
+ # there doesn't appear to be a way to tell Bazel to limit their
+ # concurrency, only disable it entirely with exclusive.
+ "exclusive",
+ # The default_test_runner() assumes it can write to the user's home
+ # directory for caching purposes. Give it access.
+ "no-sandbox",
+ # The CI RBE setup can't successfully run these tests remotely.
+ "no-remote-exec",
+ # A special tag is used so CI can run them as a separate job.
+ "integration-test",
+ ],
+ **kwargs
+ )
diff --git a/tests/pip_repository_entry_points/.bazelrc b/tests/integration/pip_repository_entry_points/.bazelrc
index b9c4c27..936806d 100644
--- a/tests/pip_repository_entry_points/.bazelrc
+++ b/tests/integration/pip_repository_entry_points/.bazelrc
@@ -5,3 +5,7 @@ startup --windows_enable_symlinks
# https://docs.bazel.build/versions/main/best-practices.html#using-the-bazelrc-file
try-import %workspace%/user.bazelrc
+
+# The requirements.bzl entry_point functions aren't supported under bzlmod.
+# They are replaced by py_console_script_binary, which already has tests
+build --noexperimental_enable_bzlmod
diff --git a/examples/pip_install/.gitignore b/tests/integration/pip_repository_entry_points/.gitignore
index e5ae073..e5ae073 100644
--- a/examples/pip_install/.gitignore
+++ b/tests/integration/pip_repository_entry_points/.gitignore
diff --git a/tests/integration/pip_repository_entry_points/BUILD.bazel b/tests/integration/pip_repository_entry_points/BUILD.bazel
new file mode 100644
index 0000000..c39b1f0
--- /dev/null
+++ b/tests/integration/pip_repository_entry_points/BUILD.bazel
@@ -0,0 +1,32 @@
+load("@pip//:requirements.bzl", "entry_point")
+load("@rules_python//python:defs.bzl", "py_test")
+load("@rules_python//python:pip.bzl", "compile_pip_requirements")
+
+# This rule adds a convenient way to update the requirements file.
+compile_pip_requirements(
+ name = "requirements",
+ src = "requirements.in",
+ requirements_windows = ":requirements_windows.txt",
+)
+
+pip_sphinx = entry_point(
+ pkg = "sphinx",
+ script = "sphinx-build",
+)
+
+pip_yamllint = entry_point("yamllint")
+
+py_test(
+ name = "pip_parse_entry_points_test",
+ srcs = ["pip_repository_entry_points_test.py"],
+ data = [
+ pip_sphinx,
+ pip_yamllint,
+ ],
+ env = {
+ "SPHINX_BUILD_ENTRY_POINT": "$(rootpath {})".format(pip_sphinx),
+ "YAMLLINT_ENTRY_POINT": "$(rootpath {})".format(pip_yamllint),
+ },
+ main = "pip_repository_entry_points_test.py",
+ deps = ["@rules_python//python/runfiles"],
+)
diff --git a/tests/pip_repository_entry_points/WORKSPACE b/tests/integration/pip_repository_entry_points/WORKSPACE
index 1afd68c..0ae087b 100644
--- a/tests/pip_repository_entry_points/WORKSPACE
+++ b/tests/integration/pip_repository_entry_points/WORKSPACE
@@ -1,8 +1,8 @@
-workspace(name = "pip_repository_annotations_example")
+workspace(name = "pip_entry_points_example")
local_repository(
name = "rules_python",
- path = "../..",
+ path = "../../..",
)
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
@@ -17,28 +17,16 @@ python_register_toolchains(
)
load("@python310//:defs.bzl", "interpreter")
-load("@rules_python//python:pip.bzl", "pip_install", "pip_parse")
+load("@rules_python//python:pip.bzl", "pip_parse")
# For a more thorough example of `pip_parse`. See `@rules_python//examples/pip_parse`
pip_parse(
- name = "pip_parsed",
+ name = "pip",
python_interpreter_target = interpreter,
requirements_lock = "//:requirements.txt",
requirements_windows = "//:requirements_windows.txt",
)
-load("@pip_parsed//:requirements.bzl", install_pip_parse_deps = "install_deps")
+load("@pip//:requirements.bzl", "install_deps")
-install_pip_parse_deps()
-
-# For a more thorough example of `pip_install`. See `@rules_python//examples/pip_install`
-pip_install(
- name = "pip_installed",
- python_interpreter_target = interpreter,
- requirements = "//:requirements.txt",
- requirements_windows = "//:requirements_windows.txt",
-)
-
-load("@pip_installed//:requirements.bzl", install_pip_install_deps = "install_deps")
-
-install_pip_install_deps()
+install_deps()
diff --git a/tests/pip_repository_entry_points/pip_repository_entry_points_test.py b/tests/integration/pip_repository_entry_points/pip_repository_entry_points_test.py
index 0375153..0375153 100644
--- a/tests/pip_repository_entry_points/pip_repository_entry_points_test.py
+++ b/tests/integration/pip_repository_entry_points/pip_repository_entry_points_test.py
diff --git a/tests/integration/pip_repository_entry_points/requirements.in b/tests/integration/pip_repository_entry_points/requirements.in
new file mode 100644
index 0000000..f5391eb
--- /dev/null
+++ b/tests/integration/pip_repository_entry_points/requirements.in
@@ -0,0 +1,8 @@
+sphinx==4.3.2
+yamllint>=1.28.0
+
+# Last available for Ubuntu python3.6
+setuptools==65.5.1
+
+certifi>=2023.7.22 # https://security.snyk.io/vuln/SNYK-PYTHON-CERTIFI-5805047
+
diff --git a/tests/pip_repository_entry_points/requirements.txt b/tests/integration/pip_repository_entry_points/requirements.txt
index a93facc..1ef1f9d 100644
--- a/tests/pip_repository_entry_points/requirements.txt
+++ b/tests/integration/pip_repository_entry_points/requirements.txt
@@ -12,10 +12,12 @@ babel==2.9.1 \
--hash=sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9 \
--hash=sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0
# via sphinx
-certifi==2021.10.8 \
- --hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872 \
- --hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569
- # via requests
+certifi==2023.7.22 \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+ # via
+ # -r requirements.in
+ # requests
charset-normalizer==2.0.10 \
--hash=sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd \
--hash=sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455
@@ -166,13 +168,6 @@ requests==2.27.1 \
--hash=sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61 \
--hash=sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d
# via sphinx
-setuptools==59.6.0 \
- --hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
- --hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
- # via
- # -r requirements.in
- # sphinx
- # yamllint
snowballstemmer==2.2.0 \
--hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
--hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
@@ -213,3 +208,12 @@ yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.5.1 \
+ --hash=sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31 \
+ --hash=sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f
+ # via
+ # -r requirements.in
+ # sphinx
+ # yamllint
diff --git a/tests/pip_repository_entry_points/requirements_windows.txt b/tests/integration/pip_repository_entry_points/requirements_windows.txt
index 651e2b5..aeff522 100644
--- a/tests/pip_repository_entry_points/requirements_windows.txt
+++ b/tests/integration/pip_repository_entry_points/requirements_windows.txt
@@ -12,10 +12,12 @@ babel==2.9.1 \
--hash=sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9 \
--hash=sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0
# via sphinx
-certifi==2021.10.8 \
- --hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872 \
- --hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569
- # via requests
+certifi==2023.7.22 \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+ # via
+ # -r requirements.in
+ # requests
charset-normalizer==2.0.10 \
--hash=sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd \
--hash=sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455
@@ -119,9 +121,9 @@ pathspec==0.9.0 \
--hash=sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a \
--hash=sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1
# via yamllint
-pygments==2.11.2 \
- --hash=sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65 \
- --hash=sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a
+pygments==2.15.0 \
+ --hash=sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094 \
+ --hash=sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500
# via sphinx
pyparsing==3.0.6 \
--hash=sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4 \
@@ -166,17 +168,10 @@ pyyaml==6.0 \
--hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
--hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
# via yamllint
-requests==2.27.1 \
- --hash=sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61 \
- --hash=sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d
+requests==2.31.0 \
+ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
+ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
# via sphinx
-setuptools==59.6.0 \
- --hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
- --hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
- # via
- # -r requirements.in
- # sphinx
- # yamllint
snowballstemmer==2.2.0 \
--hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
--hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
@@ -209,11 +204,20 @@ sphinxcontrib-serializinghtml==1.1.5 \
--hash=sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd \
--hash=sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952
# via sphinx
-urllib3==1.26.7 \
- --hash=sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece \
- --hash=sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via requests
yamllint==1.28.0 \
--hash=sha256:89bb5b5ac33b1ade059743cf227de73daa34d5e5a474b06a5e17fc16583b0cf2 \
--hash=sha256:9e3d8ddd16d0583214c5fdffe806c9344086721f107435f68bad990e5a88826b
# via -r requirements.in
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==65.5.1 \
+ --hash=sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31 \
+ --hash=sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f
+ # via
+ # -r requirements.in
+ # sphinx
+ # yamllint
diff --git a/tests/integration/py_cc_toolchain_registered/.bazelrc b/tests/integration/py_cc_toolchain_registered/.bazelrc
new file mode 100644
index 0000000..741d758
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/.bazelrc
@@ -0,0 +1,2 @@
+# This aids debugging on failure
+build --toolchain_resolution_debug=python
diff --git a/tests/integration/py_cc_toolchain_registered/BUILD.bazel b/tests/integration/py_cc_toolchain_registered/BUILD.bazel
new file mode 100644
index 0000000..9c9275c
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/BUILD.bazel
@@ -0,0 +1,19 @@
+# Copyright 2024 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.
+
+load(":defs.bzl", "py_cc_toolchain_available_test")
+
+# Simple test to verify that the py_cc_toolchain is registered and available
+# by default (for bzlmod) and when users setup a hermetic toolchain (workspace)
+py_cc_toolchain_available_test(name = "py_cc_toolchain_available_test")
diff --git a/tests/integration/py_cc_toolchain_registered/MODULE.bazel b/tests/integration/py_cc_toolchain_registered/MODULE.bazel
new file mode 100644
index 0000000..ad3b813
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/MODULE.bazel
@@ -0,0 +1,7 @@
+module(name = "py_cc_toolchain_registered")
+
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+ module_name = "rules_python",
+ path = "../../..",
+)
diff --git a/tests/integration/py_cc_toolchain_registered/WORKSPACE b/tests/integration/py_cc_toolchain_registered/WORKSPACE
new file mode 100644
index 0000000..de90854
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/WORKSPACE
@@ -0,0 +1,13 @@
+local_repository(
+ name = "rules_python",
+ path = "../../..",
+)
+
+load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
+
+py_repositories()
+
+python_register_toolchains(
+ name = "python_3_11",
+ python_version = "3.11",
+)
diff --git a/tests/integration/py_cc_toolchain_registered/defs.bzl b/tests/integration/py_cc_toolchain_registered/defs.bzl
new file mode 100644
index 0000000..65d6184
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/defs.bzl
@@ -0,0 +1,38 @@
+# 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.
+"""Defs to implement tests."""
+
+def _py_cc_toolchain_available_test_impl(ctx):
+ toolchain = ctx.toolchains["@rules_python//python/cc:toolchain_type"]
+
+ if toolchain == None:
+ fail("expected @rules_python//python/cc:toolchain_type toolchain " +
+ "to be found, but it was not found")
+
+ executable = ctx.actions.declare_file(ctx.label.name)
+ ctx.actions.write(executable, "# no-op file", is_executable = True)
+ return [DefaultInfo(
+ executable = executable,
+ )]
+
+py_cc_toolchain_available_test = rule(
+ implementation = _py_cc_toolchain_available_test_impl,
+ toolchains = [
+ config_common.toolchain_type(
+ "@rules_python//python/cc:toolchain_type",
+ mandatory = False,
+ ),
+ ],
+ test = True,
+)
diff --git a/tests/pip_hub_repository/render_pkg_aliases/BUILD.bazel b/tests/pip_hub_repository/render_pkg_aliases/BUILD.bazel
new file mode 100644
index 0000000..f2e0126
--- /dev/null
+++ b/tests/pip_hub_repository/render_pkg_aliases/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":render_pkg_aliases_test.bzl", "render_pkg_aliases_test_suite")
+
+render_pkg_aliases_test_suite(name = "render_pkg_aliases_tests")
diff --git a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
new file mode 100644
index 0000000..dff7cd0
--- /dev/null
+++ b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
@@ -0,0 +1,338 @@
+# 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.
+
+"""render_pkg_aliases tests"""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/private:render_pkg_aliases.bzl", "render_pkg_aliases") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_legacy_aliases(env):
+ actual = render_pkg_aliases(
+ bzl_packages = ["foo"],
+ repo_name = "pypi",
+ )
+
+ want = {
+ "foo/BUILD.bazel": """\
+package(default_visibility = ["//visibility:public"])
+
+alias(
+ name = "foo",
+ actual = ":pkg",
+)
+
+alias(
+ name = "pkg",
+ actual = "@pypi_foo//:pkg",
+)
+
+alias(
+ name = "whl",
+ actual = "@pypi_foo//:whl",
+)
+
+alias(
+ name = "data",
+ actual = "@pypi_foo//:data",
+)
+
+alias(
+ name = "dist_info",
+ actual = "@pypi_foo//:dist_info",
+)""",
+ }
+
+ env.expect.that_dict(actual).contains_exactly(want)
+
+_tests.append(_test_legacy_aliases)
+
+def _test_all_legacy_aliases_are_created(env):
+ actual = render_pkg_aliases(
+ bzl_packages = ["foo", "bar"],
+ repo_name = "pypi",
+ )
+
+ want_files = ["bar/BUILD.bazel", "foo/BUILD.bazel"]
+
+ env.expect.that_dict(actual).keys().contains_exactly(want_files)
+
+_tests.append(_test_all_legacy_aliases_are_created)
+
+def _test_bzlmod_aliases(env):
+ actual = render_pkg_aliases(
+ default_version = "3.2.3",
+ repo_name = "pypi",
+ rules_python = "rules_python",
+ whl_map = {
+ "bar-baz": ["3.2.3"],
+ },
+ )
+
+ want = {
+ "bar_baz/BUILD.bazel": """\
+package(default_visibility = ["//visibility:public"])
+
+alias(
+ name = "bar_baz",
+ actual = ":pkg",
+)
+
+alias(
+ name = "pkg",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
+ "//conditions:default": "@pypi_32_bar_baz//:pkg",
+ },
+ ),
+)
+
+alias(
+ name = "whl",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
+ "//conditions:default": "@pypi_32_bar_baz//:whl",
+ },
+ ),
+)
+
+alias(
+ name = "data",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
+ "//conditions:default": "@pypi_32_bar_baz//:data",
+ },
+ ),
+)
+
+alias(
+ name = "dist_info",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
+ "//conditions:default": "@pypi_32_bar_baz//:dist_info",
+ },
+ ),
+)""",
+ }
+
+ env.expect.that_dict(actual).contains_exactly(want)
+
+_tests.append(_test_bzlmod_aliases)
+
+def _test_bzlmod_aliases_with_no_default_version(env):
+ actual = render_pkg_aliases(
+ default_version = None,
+ repo_name = "pypi",
+ rules_python = "rules_python",
+ whl_map = {
+ "bar-baz": ["3.2.3", "3.1.3"],
+ },
+ )
+
+ want_key = "bar_baz/BUILD.bazel"
+ want_content = """\
+package(default_visibility = ["//visibility:public"])
+
+_NO_MATCH_ERROR = \"\"\"\\
+No matching wheel for current configuration's Python version.
+
+The current build configuration's Python version doesn't match any of the Python
+versions available for this wheel. This wheel supports the following Python versions:
+ 3.1.3, 3.2.3
+
+As matched by the `@rules_python//python/config_settings:is_python_<version>`
+configuration settings.
+
+To determine the current configuration's Python version, run:
+ `bazel config <config id>` (shown further below)
+and look for
+ rules_python//python/config_settings:python_version
+
+If the value is missing, then the "default" Python version is being used,
+which has a "null" version value and will not match version constraints.
+\"\"\"
+
+alias(
+ name = "bar_baz",
+ actual = ":pkg",
+)
+
+alias(
+ name = "pkg",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)
+
+alias(
+ name = "whl",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)
+
+alias(
+ name = "data",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)
+
+alias(
+ name = "dist_info",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)"""
+
+ env.expect.that_collection(actual.keys()).contains_exactly([want_key])
+ env.expect.that_str(actual[want_key]).equals(want_content)
+
+_tests.append(_test_bzlmod_aliases_with_no_default_version)
+
+def _test_bzlmod_aliases_for_non_root_modules(env):
+ actual = render_pkg_aliases(
+ default_version = "3.2.4",
+ repo_name = "pypi",
+ rules_python = "rules_python",
+ whl_map = {
+ "bar-baz": ["3.2.3", "3.1.3"],
+ },
+ )
+
+ want_key = "bar_baz/BUILD.bazel"
+ want_content = """\
+package(default_visibility = ["//visibility:public"])
+
+_NO_MATCH_ERROR = \"\"\"\\
+No matching wheel for current configuration's Python version.
+
+The current build configuration's Python version doesn't match any of the Python
+versions available for this wheel. This wheel supports the following Python versions:
+ 3.1.3, 3.2.3
+
+As matched by the `@rules_python//python/config_settings:is_python_<version>`
+configuration settings.
+
+To determine the current configuration's Python version, run:
+ `bazel config <config id>` (shown further below)
+and look for
+ rules_python//python/config_settings:python_version
+
+If the value is missing, then the "default" Python version is being used,
+which has a "null" version value and will not match version constraints.
+\"\"\"
+
+alias(
+ name = "bar_baz",
+ actual = ":pkg",
+)
+
+alias(
+ name = "pkg",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)
+
+alias(
+ name = "whl",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)
+
+alias(
+ name = "data",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)
+
+alias(
+ name = "dist_info",
+ actual = select(
+ {
+ "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
+ },
+ no_match_error = _NO_MATCH_ERROR,
+ ),
+)"""
+
+ env.expect.that_collection(actual.keys()).contains_exactly([want_key])
+ env.expect.that_str(actual[want_key]).equals(want_content)
+
+_tests.append(_test_bzlmod_aliases_for_non_root_modules)
+
+def _test_bzlmod_aliases_are_created_for_all_wheels(env):
+ actual = render_pkg_aliases(
+ default_version = "3.2.3",
+ repo_name = "pypi",
+ rules_python = "rules_python",
+ whl_map = {
+ "bar": ["3.1.2", "3.2.3"],
+ "foo": ["3.1.2", "3.2.3"],
+ },
+ )
+
+ want_files = [
+ "bar/BUILD.bazel",
+ "foo/BUILD.bazel",
+ ]
+
+ env.expect.that_dict(actual).keys().contains_exactly(want_files)
+
+_tests.append(_test_bzlmod_aliases_are_created_for_all_wheels)
+
+def render_pkg_aliases_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)
diff --git a/tests/pip_install/BUILD.bazel b/tests/pip_install/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/pip_install/BUILD.bazel
diff --git a/tests/pip_install/group_library/BUILD.bazel b/tests/pip_install/group_library/BUILD.bazel
new file mode 100644
index 0000000..5a27e11
--- /dev/null
+++ b/tests/pip_install/group_library/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":generate_build_bazel_tests.bzl", "generate_build_bazel_test_suite")
+
+generate_build_bazel_test_suite(name = "generate_build_bazel_tests")
diff --git a/tests/pip_install/group_library/generate_build_bazel_tests.bzl b/tests/pip_install/group_library/generate_build_bazel_tests.bzl
new file mode 100644
index 0000000..e7d6b44
--- /dev/null
+++ b/tests/pip_install/group_library/generate_build_bazel_tests.bzl
@@ -0,0 +1,57 @@
+# 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.
+
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/pip_install/private:generate_group_library_build_bazel.bzl", "generate_group_library_build_bazel") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_simple(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+
+
+## Group vbap
+
+filegroup(
+ name = "vbap_whl",
+ srcs = [],
+ data = ["@pypi_oletools//:_whl", "@pypi_pcodedmp//:_whl"],
+ visibility = ["@pypi_oletools//:__pkg__", "@pypi_pcodedmp//:__pkg__"],
+)
+
+py_library(
+ name = "vbap_pkg",
+ srcs = [],
+ deps = ["@pypi_oletools//:_pkg", "@pypi_pcodedmp//:_pkg"],
+ visibility = ["@pypi_oletools//:__pkg__", "@pypi_pcodedmp//:__pkg__"],
+)
+"""
+ actual = generate_group_library_build_bazel(
+ repo_prefix = "pypi_",
+ groups = {"vbap": ["oletools", "pcodedmp"]},
+ )
+ env.expect.that_str(actual).equals(want)
+
+_tests.append(_test_simple)
+
+def generate_build_bazel_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)
diff --git a/tests/pip_install/whl_library/BUILD.bazel b/tests/pip_install/whl_library/BUILD.bazel
new file mode 100644
index 0000000..5a27e11
--- /dev/null
+++ b/tests/pip_install/whl_library/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":generate_build_bazel_tests.bzl", "generate_build_bazel_test_suite")
+
+generate_build_bazel_test_suite(name = "generate_build_bazel_tests")
diff --git a/tests/pip_install/whl_library/generate_build_bazel_tests.bzl b/tests/pip_install/whl_library/generate_build_bazel_tests.bzl
new file mode 100644
index 0000000..b89477f
--- /dev/null
+++ b/tests/pip_install/whl_library/generate_build_bazel_tests.bzl
@@ -0,0 +1,397 @@
+# 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.
+
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/pip_install/private:generate_whl_library_build_bazel.bzl", "generate_whl_library_build_bazel") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_simple(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "dist_info",
+ srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "data",
+ srcs = glob(["data/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "_whl",
+ srcs = ["foo.whl"],
+ data = [
+ "@pypi_bar_baz//:whl",
+ "@pypi_foo//:whl",
+ ] + select(
+ {
+ "@platforms//os:windows": ["@pypi_colorama//:whl"],
+ "//conditions:default": [],
+ },
+ ),
+ visibility = ["//visibility:private"],
+)
+
+py_library(
+ name = "_pkg",
+ srcs = glob(
+ ["site-packages/**/*.py"],
+ exclude=[],
+ # Empty sources are allowed to support wheels that don't have any
+ # pure-Python code, e.g. pymssql, which is written in Cython.
+ allow_empty = True,
+ ),
+ data = [] + glob(
+ ["site-packages/**/*"],
+ exclude=["**/* *", "**/*.py", "**/*.pyc", "**/*.pyc.*", "**/*.dist-info/RECORD"],
+ ),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["site-packages"],
+ deps = [
+ "@pypi_bar_baz//:pkg",
+ "@pypi_foo//:pkg",
+ ] + select(
+ {
+ "@platforms//os:windows": ["@pypi_colorama//:pkg"],
+ "//conditions:default": [],
+ },
+ ),
+ tags = ["tag1", "tag2"],
+ visibility = ["//visibility:private"],
+)
+
+alias(
+ name = "pkg",
+ actual = "_pkg",
+)
+
+alias(
+ name = "whl",
+ actual = "_whl",
+)
+"""
+ actual = generate_whl_library_build_bazel(
+ repo_prefix = "pypi_",
+ whl_name = "foo.whl",
+ dependencies = ["foo", "bar-baz"],
+ dependencies_by_platform = {"@platforms//os:windows": ["colorama"]},
+ data_exclude = [],
+ tags = ["tag1", "tag2"],
+ entry_points = {},
+ annotation = None,
+ )
+ env.expect.that_str(actual).equals(want)
+
+_tests.append(_test_simple)
+
+def _test_with_annotation(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "dist_info",
+ srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "data",
+ srcs = glob(["data/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "_whl",
+ srcs = ["foo.whl"],
+ data = [
+ "@pypi_bar_baz//:whl",
+ "@pypi_foo//:whl",
+ ],
+ visibility = ["//visibility:private"],
+)
+
+py_library(
+ name = "_pkg",
+ srcs = glob(
+ ["site-packages/**/*.py"],
+ exclude=["srcs_exclude_all"],
+ # Empty sources are allowed to support wheels that don't have any
+ # pure-Python code, e.g. pymssql, which is written in Cython.
+ allow_empty = True,
+ ),
+ data = ["file_dest", "exec_dest"] + glob(
+ ["site-packages/**/*"],
+ exclude=["**/* *", "**/*.py", "**/*.pyc", "**/*.pyc.*", "**/*.dist-info/RECORD", "data_exclude_all"],
+ ),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["site-packages"],
+ deps = [
+ "@pypi_bar_baz//:pkg",
+ "@pypi_foo//:pkg",
+ ],
+ tags = ["tag1", "tag2"],
+ visibility = ["//visibility:private"],
+)
+
+alias(
+ name = "pkg",
+ actual = "_pkg",
+)
+
+alias(
+ name = "whl",
+ actual = "_whl",
+)
+
+copy_file(
+ name = "file_dest.copy",
+ src = "file_src",
+ out = "file_dest",
+ is_executable = False,
+)
+
+copy_file(
+ name = "exec_dest.copy",
+ src = "exec_src",
+ out = "exec_dest",
+ is_executable = True,
+)
+
+# SOMETHING SPECIAL AT THE END
+"""
+ actual = generate_whl_library_build_bazel(
+ repo_prefix = "pypi_",
+ whl_name = "foo.whl",
+ dependencies = ["foo", "bar-baz"],
+ dependencies_by_platform = {},
+ data_exclude = [],
+ tags = ["tag1", "tag2"],
+ entry_points = {},
+ annotation = struct(
+ copy_files = {"file_src": "file_dest"},
+ copy_executables = {"exec_src": "exec_dest"},
+ data = [],
+ data_exclude_glob = ["data_exclude_all"],
+ srcs_exclude_glob = ["srcs_exclude_all"],
+ additive_build_content = """# SOMETHING SPECIAL AT THE END""",
+ ),
+ )
+ env.expect.that_str(actual).equals(want)
+
+_tests.append(_test_with_annotation)
+
+def _test_with_entry_points(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "dist_info",
+ srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "data",
+ srcs = glob(["data/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "_whl",
+ srcs = ["foo.whl"],
+ data = [
+ "@pypi_bar_baz//:whl",
+ "@pypi_foo//:whl",
+ ],
+ visibility = ["//visibility:private"],
+)
+
+py_library(
+ name = "_pkg",
+ srcs = glob(
+ ["site-packages/**/*.py"],
+ exclude=[],
+ # Empty sources are allowed to support wheels that don't have any
+ # pure-Python code, e.g. pymssql, which is written in Cython.
+ allow_empty = True,
+ ),
+ data = [] + glob(
+ ["site-packages/**/*"],
+ exclude=["**/* *", "**/*.py", "**/*.pyc", "**/*.pyc.*", "**/*.dist-info/RECORD"],
+ ),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["site-packages"],
+ deps = [
+ "@pypi_bar_baz//:pkg",
+ "@pypi_foo//:pkg",
+ ],
+ tags = ["tag1", "tag2"],
+ visibility = ["//visibility:private"],
+)
+
+alias(
+ name = "pkg",
+ actual = "_pkg",
+)
+
+alias(
+ name = "whl",
+ actual = "_whl",
+)
+
+py_binary(
+ name = "rules_python_wheel_entry_point_fizz",
+ srcs = ["buzz.py"],
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["."],
+ deps = [":pkg"],
+)
+"""
+ actual = generate_whl_library_build_bazel(
+ repo_prefix = "pypi_",
+ whl_name = "foo.whl",
+ dependencies = ["foo", "bar-baz"],
+ dependencies_by_platform = {},
+ data_exclude = [],
+ tags = ["tag1", "tag2"],
+ entry_points = {"fizz": "buzz.py"},
+ annotation = None,
+ )
+ env.expect.that_str(actual).equals(want)
+
+_tests.append(_test_with_entry_points)
+
+def _test_group_member(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "dist_info",
+ srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "data",
+ srcs = glob(["data/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "_whl",
+ srcs = ["foo.whl"],
+ data = ["@pypi_bar_baz//:whl"] + select(
+ {
+ ":is_linux_x86_64": [
+ "@pypi_box//:whl",
+ "@pypi_box_amd64//:whl",
+ ],
+ "@platforms//os:linux": ["@pypi_box//:whl"],
+ "//conditions:default": [],
+ },
+ ),
+ visibility = ["@pypi__groups//:__pkg__"],
+)
+
+py_library(
+ name = "_pkg",
+ srcs = glob(
+ ["site-packages/**/*.py"],
+ exclude=[],
+ # Empty sources are allowed to support wheels that don't have any
+ # pure-Python code, e.g. pymssql, which is written in Cython.
+ allow_empty = True,
+ ),
+ data = [] + glob(
+ ["site-packages/**/*"],
+ exclude=["**/* *", "**/*.py", "**/*.pyc", "**/*.pyc.*", "**/*.dist-info/RECORD"],
+ ),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["site-packages"],
+ deps = ["@pypi_bar_baz//:pkg"] + select(
+ {
+ ":is_linux_x86_64": [
+ "@pypi_box//:pkg",
+ "@pypi_box_amd64//:pkg",
+ ],
+ "@platforms//os:linux": ["@pypi_box//:pkg"],
+ "//conditions:default": [],
+ },
+ ),
+ tags = [],
+ visibility = ["@pypi__groups//:__pkg__"],
+)
+
+alias(
+ name = "pkg",
+ actual = "@pypi__groups//:qux_pkg",
+)
+
+alias(
+ name = "whl",
+ actual = "@pypi__groups//:qux_whl",
+)
+
+config_setting(
+ name = "is_linux_x86_64",
+ constraint_values = [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+ visibility = ["//visibility:private"],
+)
+"""
+ actual = generate_whl_library_build_bazel(
+ repo_prefix = "pypi_",
+ whl_name = "foo.whl",
+ dependencies = ["foo", "bar-baz", "qux"],
+ dependencies_by_platform = {
+ "linux_x86_64": ["box", "box-amd64"],
+ "windows_x86_64": ["fox"],
+ "@platforms//os:linux": ["box"], # buildifier: disable=unsorted-dict-items
+ },
+ tags = [],
+ entry_points = {},
+ data_exclude = [],
+ annotation = None,
+ group_name = "qux",
+ group_deps = ["foo", "fox", "qux"],
+ )
+ env.expect.that_str(actual).equals(want)
+
+_tests.append(_test_group_member)
+
+def generate_build_bazel_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)
diff --git a/tests/pip_repository_entry_points/.gitignore b/tests/pip_repository_entry_points/.gitignore
deleted file mode 100644
index e5ae073..0000000
--- a/tests/pip_repository_entry_points/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# git ignore patterns
-
-/bazel-*
-user.bazelrc
diff --git a/tests/pip_repository_entry_points/BUILD.bazel b/tests/pip_repository_entry_points/BUILD.bazel
deleted file mode 100644
index 81c01c3..0000000
--- a/tests/pip_repository_entry_points/BUILD.bazel
+++ /dev/null
@@ -1,55 +0,0 @@
-load("@pip_installed//:requirements.bzl", installed_entry_point = "entry_point")
-load("@pip_parsed//:requirements.bzl", parsed_entry_point = "entry_point")
-load("@rules_python//python:defs.bzl", "py_test")
-load("@rules_python//python:pip.bzl", "compile_pip_requirements")
-
-# This rule adds a convenient way to update the requirements file.
-compile_pip_requirements(
- name = "requirements",
- extra_args = ["--allow-unsafe"],
- requirements_windows = ":requirements_windows.txt",
-)
-
-pip_parsed_sphinx = parsed_entry_point(
- pkg = "sphinx",
- script = "sphinx-build",
-)
-
-pip_parsed_yamllint = parsed_entry_point("yamllint")
-
-py_test(
- name = "pip_parse_entry_points_test",
- srcs = ["pip_repository_entry_points_test.py"],
- data = [
- pip_parsed_sphinx,
- pip_parsed_yamllint,
- ],
- env = {
- "SPHINX_BUILD_ENTRY_POINT": "$(rootpath {})".format(pip_parsed_sphinx),
- "YAMLLINT_ENTRY_POINT": "$(rootpath {})".format(pip_parsed_yamllint),
- },
- main = "pip_repository_entry_points_test.py",
- deps = ["@rules_python//python/runfiles"],
-)
-
-pip_installed_sphinx = installed_entry_point(
- pkg = "sphinx",
- script = "sphinx-build",
-)
-
-pip_installed_yamllint = installed_entry_point("yamllint")
-
-py_test(
- name = "pip_install_annotations_test",
- srcs = ["pip_repository_entry_points_test.py"],
- data = [
- pip_installed_sphinx,
- pip_installed_yamllint,
- ],
- env = {
- "SPHINX_BUILD_ENTRY_POINT": "$(rootpath {})".format(pip_installed_sphinx),
- "YAMLLINT_ENTRY_POINT": "$(rootpath {})".format(pip_installed_yamllint),
- },
- main = "pip_repository_entry_points_test.py",
- deps = ["@rules_python//python/runfiles"],
-)
diff --git a/tests/pip_repository_entry_points/requirements.in b/tests/pip_repository_entry_points/requirements.in
deleted file mode 100644
index 2cc4625..0000000
--- a/tests/pip_repository_entry_points/requirements.in
+++ /dev/null
@@ -1,5 +0,0 @@
-sphinx==4.3.2
-yamllint>=1.28.0
-
-# Last avialable for ubuntu python3.6
-setuptools==59.6.0
diff --git a/tests/private/parse_whl_name/BUILD.bazel b/tests/private/parse_whl_name/BUILD.bazel
new file mode 100644
index 0000000..c2fb365
--- /dev/null
+++ b/tests/private/parse_whl_name/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":parse_whl_name_tests.bzl", "parse_whl_name_test_suite")
+
+parse_whl_name_test_suite(name = "parse_whl_name_tests")
diff --git a/tests/private/parse_whl_name/parse_whl_name_tests.bzl b/tests/private/parse_whl_name/parse_whl_name_tests.bzl
new file mode 100644
index 0000000..c249f9f
--- /dev/null
+++ b/tests/private/parse_whl_name/parse_whl_name_tests.bzl
@@ -0,0 +1,72 @@
+# 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.
+
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/private:parse_whl_name.bzl", "parse_whl_name") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_simple(env):
+ got = parse_whl_name("foo-1.2.3-py3-none-any.whl")
+ env.expect.that_str(got.distribution).equals("foo")
+ env.expect.that_str(got.version).equals("1.2.3")
+ env.expect.that_str(got.abi_tag).equals("none")
+ env.expect.that_str(got.platform_tag).equals("any")
+ env.expect.that_str(got.python_tag).equals("py3")
+ env.expect.that_str(got.build_tag).equals(None)
+
+_tests.append(_test_simple)
+
+def _test_with_build_tag(env):
+ got = parse_whl_name("foo-3.2.1-9999-py2.py3-none-any.whl")
+ env.expect.that_str(got.distribution).equals("foo")
+ env.expect.that_str(got.version).equals("3.2.1")
+ env.expect.that_str(got.abi_tag).equals("none")
+ env.expect.that_str(got.platform_tag).equals("any")
+ env.expect.that_str(got.python_tag).equals("py2.py3")
+ env.expect.that_str(got.build_tag).equals("9999")
+
+_tests.append(_test_with_build_tag)
+
+def _test_multiple_platforms(env):
+ got = parse_whl_name("bar-3.2.1-py3-abi3-manylinux1.manylinux2.whl")
+ env.expect.that_str(got.distribution).equals("bar")
+ env.expect.that_str(got.version).equals("3.2.1")
+ env.expect.that_str(got.abi_tag).equals("abi3")
+ env.expect.that_str(got.platform_tag).equals("manylinux1.manylinux2")
+ env.expect.that_str(got.python_tag).equals("py3")
+ env.expect.that_str(got.build_tag).equals(None)
+
+_tests.append(_test_multiple_platforms)
+
+def _test_real_numpy_wheel(env):
+ got = parse_whl_name("numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl")
+ env.expect.that_str(got.distribution).equals("numpy")
+ env.expect.that_str(got.version).equals("1.26.1")
+ env.expect.that_str(got.abi_tag).equals("pypy39_pp73")
+ env.expect.that_str(got.platform_tag).equals("macosx_10_9_x86_64")
+ env.expect.that_str(got.python_tag).equals("pp39")
+ env.expect.that_str(got.build_tag).equals(None)
+
+_tests.append(_test_real_numpy_wheel)
+
+def parse_whl_name_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)
diff --git a/examples/pip_install/main.py b/tests/private/text_util/BUILD.bazel
index 1fb7249..c9c2106 100644
--- a/examples/pip_install/main.py
+++ b/tests/private/text_util/BUILD.bazel
@@ -12,12 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import boto3
+load(":render_tests.bzl", "render_test_suite")
-
-def the_dir():
- return dir(boto3)
-
-
-if __name__ == "__main__":
- print(the_dir())
+render_test_suite(name = "render_tests")
diff --git a/tests/private/text_util/render_tests.bzl b/tests/private/text_util/render_tests.bzl
new file mode 100644
index 0000000..7c3dddf
--- /dev/null
+++ b/tests/private/text_util/render_tests.bzl
@@ -0,0 +1,63 @@
+# 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.
+
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/private:text_util.bzl", "render") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_render_alias(env):
+ tests = [
+ struct(
+ args = dict(
+ name = "foo",
+ actual = repr("bar"),
+ ),
+ want = [
+ "alias(",
+ ' name = "foo",',
+ ' actual = "bar",',
+ ")",
+ ],
+ ),
+ struct(
+ args = dict(
+ name = "foo",
+ actual = repr("bar"),
+ visibility = ["//:__pkg__"],
+ ),
+ want = [
+ "alias(",
+ ' name = "foo",',
+ ' actual = "bar",',
+ ' visibility = ["//:__pkg__"],',
+ ")",
+ ],
+ ),
+ ]
+ for test in tests:
+ got = render.alias(**test.args)
+ env.expect.that_str(got).equals("\n".join(test.want).strip())
+
+_tests.append(_test_render_alias)
+
+def render_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)
diff --git a/tests/private/whl_target_platforms/BUILD.bazel b/tests/private/whl_target_platforms/BUILD.bazel
new file mode 100644
index 0000000..fec25af
--- /dev/null
+++ b/tests/private/whl_target_platforms/BUILD.bazel
@@ -0,0 +1,17 @@
+# 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.
+
+load(":whl_target_platforms_tests.bzl", "whl_target_platforms_test_suite")
+
+whl_target_platforms_test_suite(name = "whl_target_platforms_tests")
diff --git a/tests/private/whl_target_platforms/whl_target_platforms_tests.bzl b/tests/private/whl_target_platforms/whl_target_platforms_tests.bzl
new file mode 100644
index 0000000..9ccff0e
--- /dev/null
+++ b/tests/private/whl_target_platforms/whl_target_platforms_tests.bzl
@@ -0,0 +1,54 @@
+# 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.
+
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/private:whl_target_platforms.bzl", "whl_target_platforms") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_simple(env):
+ tests = {
+ "macosx_10_9_arm64": [
+ struct(os = "osx", cpu = "aarch64"),
+ ],
+ "macosx_10_9_universal2": [
+ struct(os = "osx", cpu = "x86_64"),
+ struct(os = "osx", cpu = "aarch64"),
+ ],
+ "manylinux1_i686.manylinux_2_17_i686": [
+ struct(os = "linux", cpu = "x86_32"),
+ ],
+ "musllinux_1_1_ppc64le": [
+ struct(os = "linux", cpu = "ppc"),
+ ],
+ "win_amd64": [
+ struct(os = "windows", cpu = "x86_64"),
+ ],
+ }
+
+ for give, want in tests.items():
+ got = whl_target_platforms(give)
+ env.expect.that_collection(got).contains_exactly(want)
+
+_tests.append(_test_simple)
+
+def whl_target_platforms_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)
diff --git a/tests/py_runtime/BUILD.bazel b/tests/py_runtime/BUILD.bazel
new file mode 100644
index 0000000..e097f0d
--- /dev/null
+++ b/tests/py_runtime/BUILD.bazel
@@ -0,0 +1,17 @@
+# 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.
+
+load(":py_runtime_tests.bzl", "py_runtime_test_suite")
+
+py_runtime_test_suite(name = "py_runtime_tests")
diff --git a/tests/py_runtime/py_runtime_tests.bzl b/tests/py_runtime/py_runtime_tests.bzl
new file mode 100644
index 0000000..9fa5e2a
--- /dev/null
+++ b/tests/py_runtime/py_runtime_tests.bzl
@@ -0,0 +1,420 @@
+# 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.
+"""Starlark tests for py_runtime rule."""
+
+load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("@rules_testing//lib:truth.bzl", "matching")
+load("@rules_testing//lib:util.bzl", rt_util = "util")
+load("//python:py_runtime.bzl", "py_runtime")
+load("//python:py_runtime_info.bzl", "PyRuntimeInfo")
+load("//tests:py_runtime_info_subject.bzl", "py_runtime_info_subject")
+load("//tests/base_rules:util.bzl", br_util = "util")
+
+_tests = []
+
+_SKIP_TEST = {
+ "target_compatible_with": ["@platforms//:incompatible"],
+}
+
+def _simple_binary_impl(ctx):
+ executable = ctx.actions.declare_file(ctx.label.name)
+ ctx.actions.write(executable, "", is_executable = True)
+ return [DefaultInfo(
+ executable = executable,
+ files = depset([executable] + ctx.files.extra_default_outputs),
+ runfiles = ctx.runfiles(ctx.files.data),
+ )]
+
+_simple_binary = rule(
+ implementation = _simple_binary_impl,
+ attrs = {
+ "data": attr.label_list(allow_files = True),
+ "extra_default_outputs": attr.label_list(allow_files = True),
+ },
+ executable = True,
+)
+
+def _test_bootstrap_template(name):
+ # The bootstrap_template arg isn't present in older Bazel versions, so
+ # we have to conditionally pass the arg and mark the test incompatible.
+ if config.enable_pystar:
+ py_runtime_kwargs = {"bootstrap_template": "bootstrap.txt"}
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {}
+ attr_values = _SKIP_TEST
+
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ interpreter_path = "/py",
+ python_version = "PY3",
+ **py_runtime_kwargs
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_bootstrap_template_impl,
+ attr_values = attr_values,
+ )
+
+def _test_bootstrap_template_impl(env, target):
+ env.expect.that_target(target).provider(
+ PyRuntimeInfo,
+ factory = py_runtime_info_subject,
+ ).bootstrap_template().path().contains("bootstrap.txt")
+
+_tests.append(_test_bootstrap_template)
+
+def _test_cannot_have_both_inbuild_and_system_interpreter(name):
+ if br_util.is_bazel_6_or_higher():
+ py_runtime_kwargs = {
+ "interpreter": "fake_interpreter",
+ "interpreter_path": "/some/path",
+ }
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {
+ "interpreter_path": "/some/path",
+ }
+ attr_values = _SKIP_TEST
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ python_version = "PY3",
+ **py_runtime_kwargs
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_cannot_have_both_inbuild_and_system_interpreter_impl,
+ expect_failure = True,
+ attr_values = attr_values,
+ )
+
+def _test_cannot_have_both_inbuild_and_system_interpreter_impl(env, target):
+ env.expect.that_target(target).failures().contains_predicate(
+ matching.str_matches("one of*interpreter*interpreter_path"),
+ )
+
+_tests.append(_test_cannot_have_both_inbuild_and_system_interpreter)
+
+def _test_cannot_specify_files_for_system_interpreter(name):
+ if br_util.is_bazel_6_or_higher():
+ py_runtime_kwargs = {"files": ["foo.txt"]}
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {}
+ attr_values = _SKIP_TEST
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ interpreter_path = "/foo",
+ python_version = "PY3",
+ **py_runtime_kwargs
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_cannot_specify_files_for_system_interpreter_impl,
+ expect_failure = True,
+ attr_values = attr_values,
+ )
+
+def _test_cannot_specify_files_for_system_interpreter_impl(env, target):
+ env.expect.that_target(target).failures().contains_predicate(
+ matching.str_matches("files*must be empty"),
+ )
+
+_tests.append(_test_cannot_specify_files_for_system_interpreter)
+
+def _test_coverage_tool_executable(name):
+ if br_util.is_bazel_6_or_higher():
+ py_runtime_kwargs = {
+ "coverage_tool": name + "_coverage_tool",
+ }
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {}
+ attr_values = _SKIP_TEST
+
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ python_version = "PY3",
+ interpreter_path = "/bogus",
+ **py_runtime_kwargs
+ )
+ rt_util.helper_target(
+ _simple_binary,
+ name = name + "_coverage_tool",
+ data = ["coverage_file1.txt", "coverage_file2.txt"],
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_coverage_tool_executable_impl,
+ attr_values = attr_values,
+ )
+
+def _test_coverage_tool_executable_impl(env, target):
+ info = env.expect.that_target(target).provider(PyRuntimeInfo, factory = py_runtime_info_subject)
+ info.coverage_tool().short_path_equals("{package}/{test_name}_coverage_tool")
+ info.coverage_files().contains_exactly([
+ "{package}/{test_name}_coverage_tool",
+ "{package}/coverage_file1.txt",
+ "{package}/coverage_file2.txt",
+ ])
+
+_tests.append(_test_coverage_tool_executable)
+
+def _test_coverage_tool_plain_files(name):
+ if br_util.is_bazel_6_or_higher():
+ py_runtime_kwargs = {
+ "coverage_tool": name + "_coverage_tool",
+ }
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {}
+ attr_values = _SKIP_TEST
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ python_version = "PY3",
+ interpreter_path = "/bogus",
+ **py_runtime_kwargs
+ )
+ rt_util.helper_target(
+ native.filegroup,
+ name = name + "_coverage_tool",
+ srcs = ["coverage_tool.py"],
+ data = ["coverage_file1.txt", "coverage_file2.txt"],
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_coverage_tool_plain_files_impl,
+ attr_values = attr_values,
+ )
+
+def _test_coverage_tool_plain_files_impl(env, target):
+ info = env.expect.that_target(target).provider(PyRuntimeInfo, factory = py_runtime_info_subject)
+ info.coverage_tool().short_path_equals("{package}/coverage_tool.py")
+ info.coverage_files().contains_exactly([
+ "{package}/coverage_tool.py",
+ "{package}/coverage_file1.txt",
+ "{package}/coverage_file2.txt",
+ ])
+
+_tests.append(_test_coverage_tool_plain_files)
+
+def _test_in_build_interpreter(name):
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ interpreter = "fake_interpreter",
+ python_version = "PY3",
+ files = ["file1.txt"],
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_in_build_interpreter_impl,
+ )
+
+def _test_in_build_interpreter_impl(env, target):
+ info = env.expect.that_target(target).provider(PyRuntimeInfo, factory = py_runtime_info_subject)
+ info.python_version().equals("PY3")
+ info.files().contains_predicate(matching.file_basename_equals("file1.txt"))
+ info.interpreter().path().contains("fake_interpreter")
+
+_tests.append(_test_in_build_interpreter)
+
+def _test_interpreter_binary_with_multiple_outputs(name):
+ rt_util.helper_target(
+ _simple_binary,
+ name = name + "_built_interpreter",
+ extra_default_outputs = ["extra_default_output.txt"],
+ data = ["runfile.txt"],
+ )
+
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ interpreter = name + "_built_interpreter",
+ python_version = "PY3",
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_interpreter_binary_with_multiple_outputs_impl,
+ )
+
+def _test_interpreter_binary_with_multiple_outputs_impl(env, target):
+ target = env.expect.that_target(target)
+ py_runtime_info = target.provider(
+ PyRuntimeInfo,
+ factory = py_runtime_info_subject,
+ )
+ py_runtime_info.interpreter().short_path_equals("{package}/{test_name}_built_interpreter")
+ py_runtime_info.files().contains_exactly([
+ "{package}/extra_default_output.txt",
+ "{package}/runfile.txt",
+ "{package}/{test_name}_built_interpreter",
+ ])
+
+ target.default_outputs().contains_exactly([
+ "{package}/extra_default_output.txt",
+ "{package}/runfile.txt",
+ "{package}/{test_name}_built_interpreter",
+ ])
+
+ target.runfiles().contains_exactly([
+ "{workspace}/{package}/runfile.txt",
+ "{workspace}/{package}/{test_name}_built_interpreter",
+ ])
+
+_tests.append(_test_interpreter_binary_with_multiple_outputs)
+
+def _test_interpreter_binary_with_single_output_and_runfiles(name):
+ rt_util.helper_target(
+ _simple_binary,
+ name = name + "_built_interpreter",
+ data = ["runfile.txt"],
+ )
+
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ interpreter = name + "_built_interpreter",
+ python_version = "PY3",
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_interpreter_binary_with_single_output_and_runfiles_impl,
+ )
+
+def _test_interpreter_binary_with_single_output_and_runfiles_impl(env, target):
+ target = env.expect.that_target(target)
+ py_runtime_info = target.provider(
+ PyRuntimeInfo,
+ factory = py_runtime_info_subject,
+ )
+ py_runtime_info.interpreter().short_path_equals("{package}/{test_name}_built_interpreter")
+ py_runtime_info.files().contains_exactly([
+ "{package}/runfile.txt",
+ "{package}/{test_name}_built_interpreter",
+ ])
+
+ target.default_outputs().contains_exactly([
+ "{package}/runfile.txt",
+ "{package}/{test_name}_built_interpreter",
+ ])
+
+ target.runfiles().contains_exactly([
+ "{workspace}/{package}/runfile.txt",
+ "{workspace}/{package}/{test_name}_built_interpreter",
+ ])
+
+_tests.append(_test_interpreter_binary_with_single_output_and_runfiles)
+
+def _test_must_have_either_inbuild_or_system_interpreter(name):
+ if br_util.is_bazel_6_or_higher():
+ py_runtime_kwargs = {}
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {
+ "interpreter_path": "/some/path",
+ }
+ attr_values = _SKIP_TEST
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ python_version = "PY3",
+ **py_runtime_kwargs
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_must_have_either_inbuild_or_system_interpreter_impl,
+ expect_failure = True,
+ attr_values = attr_values,
+ )
+
+def _test_must_have_either_inbuild_or_system_interpreter_impl(env, target):
+ env.expect.that_target(target).failures().contains_predicate(
+ matching.str_matches("one of*interpreter*interpreter_path"),
+ )
+
+_tests.append(_test_must_have_either_inbuild_or_system_interpreter)
+
+def _test_system_interpreter(name):
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ interpreter_path = "/system/python",
+ python_version = "PY3",
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_system_interpreter_impl,
+ )
+
+def _test_system_interpreter_impl(env, target):
+ env.expect.that_target(target).provider(
+ PyRuntimeInfo,
+ factory = py_runtime_info_subject,
+ ).interpreter_path().equals("/system/python")
+
+_tests.append(_test_system_interpreter)
+
+def _test_system_interpreter_must_be_absolute(name):
+ # Bazel 5.4 will entirely crash when an invalid interpreter_path
+ # is given.
+ if br_util.is_bazel_6_or_higher():
+ py_runtime_kwargs = {"interpreter_path": "relative/path"}
+ attr_values = {}
+ else:
+ py_runtime_kwargs = {"interpreter_path": "/junk/value/for/bazel5.4"}
+ attr_values = _SKIP_TEST
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_subject",
+ python_version = "PY3",
+ **py_runtime_kwargs
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_system_interpreter_must_be_absolute_impl,
+ expect_failure = True,
+ attr_values = attr_values,
+ )
+
+def _test_system_interpreter_must_be_absolute_impl(env, target):
+ env.expect.that_target(target).failures().contains_predicate(
+ matching.str_matches("must be*absolute"),
+ )
+
+_tests.append(_test_system_interpreter_must_be_absolute)
+
+def py_runtime_test_suite(name):
+ test_suite(
+ name = name,
+ tests = _tests,
+ )
diff --git a/tests/py_runtime_info_subject.bzl b/tests/py_runtime_info_subject.bzl
new file mode 100644
index 0000000..219719f
--- /dev/null
+++ b/tests/py_runtime_info_subject.bzl
@@ -0,0 +1,102 @@
+# 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.
+"""PyRuntimeInfo testing subject."""
+
+load("@rules_testing//lib:truth.bzl", "subjects")
+
+def py_runtime_info_subject(info, *, meta):
+ """Creates a new `PyRuntimeInfoSubject` for a PyRuntimeInfo provider instance.
+
+ Method: PyRuntimeInfoSubject.new
+
+ Args:
+ info: The PyRuntimeInfo object
+ meta: ExpectMeta object.
+
+ Returns:
+ A `PyRuntimeInfoSubject` struct
+ """
+
+ # buildifier: disable=uninitialized
+ public = struct(
+ # go/keep-sorted start
+ actual = info,
+ bootstrap_template = lambda *a, **k: _py_runtime_info_subject_bootstrap_template(self, *a, **k),
+ coverage_files = lambda *a, **k: _py_runtime_info_subject_coverage_files(self, *a, **k),
+ coverage_tool = lambda *a, **k: _py_runtime_info_subject_coverage_tool(self, *a, **k),
+ files = lambda *a, **k: _py_runtime_info_subject_files(self, *a, **k),
+ interpreter = lambda *a, **k: _py_runtime_info_subject_interpreter(self, *a, **k),
+ interpreter_path = lambda *a, **k: _py_runtime_info_subject_interpreter_path(self, *a, **k),
+ python_version = lambda *a, **k: _py_runtime_info_subject_python_version(self, *a, **k),
+ stub_shebang = lambda *a, **k: _py_runtime_info_subject_stub_shebang(self, *a, **k),
+ # go/keep-sorted end
+ )
+ self = struct(
+ actual = info,
+ meta = meta,
+ )
+ return public
+
+def _py_runtime_info_subject_bootstrap_template(self):
+ return subjects.file(
+ self.actual.bootstrap_template,
+ meta = self.meta.derive("bootstrap_template()"),
+ )
+
+def _py_runtime_info_subject_coverage_files(self):
+ """Returns a `DepsetFileSubject` for the `coverage_files` attribute.
+
+ Args:
+ self: implicitly added.
+ """
+ return subjects.depset_file(
+ self.actual.coverage_files,
+ meta = self.meta.derive("coverage_files()"),
+ )
+
+def _py_runtime_info_subject_coverage_tool(self):
+ return subjects.file(
+ self.actual.coverage_tool,
+ meta = self.meta.derive("coverage_tool()"),
+ )
+
+def _py_runtime_info_subject_files(self):
+ return subjects.depset_file(
+ self.actual.files,
+ meta = self.meta.derive("files()"),
+ )
+
+def _py_runtime_info_subject_interpreter(self):
+ return subjects.file(
+ self.actual.interpreter,
+ meta = self.meta.derive("interpreter()"),
+ )
+
+def _py_runtime_info_subject_interpreter_path(self):
+ return subjects.str(
+ self.actual.interpreter_path,
+ meta = self.meta.derive("interpreter_path()"),
+ )
+
+def _py_runtime_info_subject_python_version(self):
+ return subjects.str(
+ self.actual.python_version,
+ meta = self.meta.derive("python_version()"),
+ )
+
+def _py_runtime_info_subject_stub_shebang(self):
+ return subjects.str(
+ self.actual.stub_shebang,
+ meta = self.meta.derive("stub_shebang()"),
+ )
diff --git a/tests/py_runtime_pair/BUILD.bazel b/tests/py_runtime_pair/BUILD.bazel
new file mode 100644
index 0000000..6a6a4b9
--- /dev/null
+++ b/tests/py_runtime_pair/BUILD.bazel
@@ -0,0 +1,17 @@
+# 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.
+
+load(":py_runtime_pair_tests.bzl", "py_runtime_pair_test_suite")
+
+py_runtime_pair_test_suite(name = "py_runtime_pair_tests")
diff --git a/tests/py_runtime_pair/py_runtime_pair_tests.bzl b/tests/py_runtime_pair/py_runtime_pair_tests.bzl
new file mode 100644
index 0000000..236f1ba
--- /dev/null
+++ b/tests/py_runtime_pair/py_runtime_pair_tests.bzl
@@ -0,0 +1,147 @@
+# 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.
+"""Starlark tests for py_runtime_pair rule."""
+
+load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("@rules_testing//lib:truth.bzl", "matching", "subjects")
+load("@rules_testing//lib:util.bzl", rt_util = "util")
+load("//python:py_binary.bzl", "py_binary")
+load("//python:py_runtime.bzl", "py_runtime")
+load("//python:py_runtime_pair.bzl", "py_runtime_pair")
+load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo") # buildifier: disable=bzl-visibility
+load("//tests:py_runtime_info_subject.bzl", "py_runtime_info_subject")
+
+def _toolchain_factory(value, meta):
+ return subjects.struct(
+ value,
+ meta = meta,
+ attrs = {
+ "py3_runtime": py_runtime_info_subject,
+ },
+ )
+
+def _provides_builtin_py_runtime_info_impl(ctx): # @unused
+ return [BuiltinPyRuntimeInfo(
+ python_version = "PY3",
+ interpreter_path = "builtin",
+ )]
+
+_provides_builtin_py_runtime_info = rule(
+ implementation = _provides_builtin_py_runtime_info_impl,
+)
+
+_tests = []
+
+def _test_basic(name):
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_runtime",
+ interpreter = "fake_interpreter",
+ python_version = "PY3",
+ files = ["file1.txt"],
+ )
+ rt_util.helper_target(
+ py_runtime_pair,
+ name = name + "_subject",
+ py3_runtime = name + "_runtime",
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_basic_impl,
+ )
+
+def _test_basic_impl(env, target):
+ toolchain = env.expect.that_target(target).provider(
+ platform_common.ToolchainInfo,
+ factory = _toolchain_factory,
+ )
+ toolchain.py3_runtime().python_version().equals("PY3")
+ toolchain.py3_runtime().files().contains_predicate(matching.file_basename_equals("file1.txt"))
+ toolchain.py3_runtime().interpreter().path().contains("fake_interpreter")
+
+_tests.append(_test_basic)
+
+def _test_builtin_py_info_accepted(name):
+ rt_util.helper_target(
+ _provides_builtin_py_runtime_info,
+ name = name + "_runtime",
+ )
+ rt_util.helper_target(
+ py_runtime_pair,
+ name = name + "_subject",
+ py3_runtime = name + "_runtime",
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_builtin_py_info_accepted_impl,
+ )
+
+def _test_builtin_py_info_accepted_impl(env, target):
+ toolchain = env.expect.that_target(target).provider(
+ platform_common.ToolchainInfo,
+ factory = _toolchain_factory,
+ )
+ toolchain.py3_runtime().python_version().equals("PY3")
+ toolchain.py3_runtime().interpreter_path().equals("builtin")
+
+_tests.append(_test_builtin_py_info_accepted)
+
+def _test_py_runtime_pair_and_binary(name):
+ rt_util.helper_target(
+ py_runtime,
+ name = name + "_runtime",
+ interpreter_path = "/fake_interpreter",
+ python_version = "PY3",
+ )
+ rt_util.helper_target(
+ py_runtime_pair,
+ name = name + "_pair",
+ py3_runtime = name + "_runtime",
+ )
+ native.toolchain(
+ name = name + "_toolchain",
+ toolchain = name + "_pair",
+ toolchain_type = "//python:toolchain_type",
+ )
+ rt_util.helper_target(
+ py_binary,
+ name = name + "_subject",
+ srcs = [name + "_subject.py"],
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_py_runtime_pair_and_binary_impl,
+ config_settings = {
+ "//command_line_option:extra_toolchains": [
+ "//tests/py_runtime_pair:{}_toolchain".format(name),
+ "//tests/cc:all",
+ ],
+ },
+ )
+
+def _test_py_runtime_pair_and_binary_impl(env, target):
+ # Building indicates success, so nothing to assert
+ _ = env, target # @unused
+
+_tests.append(_test_py_runtime_pair_and_binary)
+
+def py_runtime_pair_test_suite(name):
+ test_suite(
+ name = name,
+ tests = _tests,
+ )
diff --git a/tools/build_defs/python/tests/py_wheel/BUILD.bazel b/tests/py_wheel/py_wheel/BUILD.bazel
index d925bb9..d925bb9 100644
--- a/tools/build_defs/python/tests/py_wheel/BUILD.bazel
+++ b/tests/py_wheel/py_wheel/BUILD.bazel
diff --git a/tools/build_defs/python/tests/py_wheel/py_wheel_tests.bzl b/tests/py_wheel/py_wheel/py_wheel_tests.bzl
index 4408592..c70163e 100644
--- a/tools/build_defs/python/tests/py_wheel/py_wheel_tests.bzl
+++ b/tests/py_wheel/py_wheel/py_wheel_tests.bzl
@@ -4,7 +4,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("//python:packaging.bzl", "py_wheel")
-load("//tools/build_defs/python/tests:util.bzl", pt_util = "util")
+load("//tests/base_rules:util.bzl", pt_util = "util")
_tests = []
diff --git a/tests/py_wheel/py_wheel_tests.bzl b/tests/py_wheel/py_wheel_tests.bzl
index e580732..3c03a1b 100644
--- a/tests/py_wheel/py_wheel_tests.bzl
+++ b/tests/py_wheel/py_wheel_tests.bzl
@@ -16,7 +16,9 @@
load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
load("@rules_testing//lib:util.bzl", rt_util = "util")
load("//python:packaging.bzl", "py_wheel")
+load("//python/private:py_wheel_normalize_pep440.bzl", "normalize_pep440") # buildifier: disable=bzl-visibility
+_basic_tests = []
_tests = []
def _test_metadata(name):
@@ -92,8 +94,109 @@ def _test_content_type_from_description_impl(env, target):
_tests.append(_test_content_type_from_description)
+def _test_pep440_normalization(env):
+ prefixes = ["v", " v", " \t\r\nv"]
+ epochs = {
+ "": ["", "0!", "00!"],
+ "1!": ["1!", "001!"],
+ "200!": ["200!", "00200!"],
+ }
+ releases = {
+ "0.1": ["0.1", "0.01"],
+ "2023.7.19": ["2023.7.19", "2023.07.19"],
+ }
+ pres = {
+ "": [""],
+ "a0": ["a", ".a", "-ALPHA0", "_alpha0", ".a0"],
+ "a4": ["alpha4", ".a04"],
+ "b0": ["b", ".b", "-BETA0", "_beta0", ".b0"],
+ "b5": ["beta05", ".b5"],
+ "rc0": ["C", "_c0", "RC", "_rc0", "-preview_0"],
+ }
+ explicit_posts = {
+ "": [""],
+ ".post0": [],
+ ".post1": [".post1", "-r1", "_rev1"],
+ }
+ implicit_posts = [[".post1", "-1"], [".post2", "-2"]]
+ devs = {
+ "": [""],
+ ".dev0": ["dev", "-DEV", "_Dev-0"],
+ ".dev9": ["DEV9", ".dev09", ".dev9"],
+ ".dev{BUILD_TIMESTAMP}": [
+ "-DEV{BUILD_TIMESTAMP}",
+ "_dev_{BUILD_TIMESTAMP}",
+ ],
+ }
+ locals = {
+ "": [""],
+ "+ubuntu.7": ["+Ubuntu_7", "+ubuntu-007"],
+ "+ubuntu.r007": ["+Ubuntu_R007"],
+ }
+ epochs = [
+ [normalized_epoch, input_epoch]
+ for normalized_epoch, input_epochs in epochs.items()
+ for input_epoch in input_epochs
+ ]
+ releases = [
+ [normalized_release, input_release]
+ for normalized_release, input_releases in releases.items()
+ for input_release in input_releases
+ ]
+ pres = [
+ [normalized_pre, input_pre]
+ for normalized_pre, input_pres in pres.items()
+ for input_pre in input_pres
+ ]
+ explicit_posts = [
+ [normalized_post, input_post]
+ for normalized_post, input_posts in explicit_posts.items()
+ for input_post in input_posts
+ ]
+ pres_and_posts = [
+ [normalized_pre + normalized_post, input_pre + input_post]
+ for normalized_pre, input_pre in pres
+ for normalized_post, input_post in explicit_posts
+ ] + [
+ [normalized_pre + normalized_post, input_pre + input_post]
+ for normalized_pre, input_pre in pres
+ for normalized_post, input_post in implicit_posts
+ if input_pre == "" or input_pre[-1].isdigit()
+ ]
+ devs = [
+ [normalized_dev, input_dev]
+ for normalized_dev, input_devs in devs.items()
+ for input_dev in input_devs
+ ]
+ locals = [
+ [normalized_local, input_local]
+ for normalized_local, input_locals in locals.items()
+ for input_local in input_locals
+ ]
+ postfixes = ["", " ", " \t\r\n"]
+ i = 0
+ for nepoch, iepoch in epochs:
+ for nrelease, irelease in releases:
+ for nprepost, iprepost in pres_and_posts:
+ for ndev, idev in devs:
+ for nlocal, ilocal in locals:
+ prefix = prefixes[i % len(prefixes)]
+ postfix = postfixes[(i // len(prefixes)) % len(postfixes)]
+ env.expect.that_str(
+ normalize_pep440(
+ prefix + iepoch + irelease + iprepost +
+ idev + ilocal + postfix,
+ ),
+ ).equals(
+ nepoch + nrelease + nprepost + ndev + nlocal,
+ )
+ i += 1
+
+_basic_tests.append(_test_pep440_normalization)
+
def py_wheel_test_suite(name):
test_suite(
name = name,
+ basic_tests = _basic_tests,
tests = _tests,
)
diff --git a/tests/pycross/0001-Add-new-file-for-testing-patch-support.patch b/tests/pycross/0001-Add-new-file-for-testing-patch-support.patch
new file mode 100644
index 0000000..fcbc309
--- /dev/null
+++ b/tests/pycross/0001-Add-new-file-for-testing-patch-support.patch
@@ -0,0 +1,17 @@
+From b2ebe6fe67ff48edaf2ae937d24b1f0b67c16f81 Mon Sep 17 00:00:00 2001
+From: Philipp Schrader <philipp.schrader@gmail.com>
+Date: Thu, 28 Sep 2023 09:02:44 -0700
+Subject: [PATCH] Add new file for testing patch support
+
+---
+ site-packages/numpy/file_added_via_patch.txt | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 site-packages/numpy/file_added_via_patch.txt
+
+diff --git a/site-packages/numpy/file_added_via_patch.txt b/site-packages/numpy/file_added_via_patch.txt
+new file mode 100644
+index 0000000..9d947a4
+--- /dev/null
++++ b/site-packages/numpy/file_added_via_patch.txt
+@@ -0,0 +1 @@
++Hello from a patch!
diff --git a/tests/pycross/BUILD.bazel b/tests/pycross/BUILD.bazel
new file mode 100644
index 0000000..52d1d18
--- /dev/null
+++ b/tests/pycross/BUILD.bazel
@@ -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.
+
+load("//python:defs.bzl", "py_test")
+load("//third_party/rules_pycross/pycross/private:wheel_library.bzl", "py_wheel_library") # buildifier: disable=bzl-visibility
+
+py_wheel_library(
+ name = "extracted_wheel_for_testing",
+ wheel = "@wheel_for_testing//file",
+)
+
+py_test(
+ name = "py_wheel_library_test",
+ srcs = [
+ "py_wheel_library_test.py",
+ ],
+ data = [
+ ":extracted_wheel_for_testing",
+ ],
+ deps = [
+ "//python/runfiles",
+ ],
+)
+
+py_wheel_library(
+ name = "patched_extracted_wheel_for_testing",
+ patch_args = [
+ "-p1",
+ ],
+ patch_tool = "patch",
+ patches = [
+ "0001-Add-new-file-for-testing-patch-support.patch",
+ ],
+ target_compatible_with = select({
+ # We don't have `patch` available on the Windows CI machines.
+ "@platforms//os:windows": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ }),
+ wheel = "@wheel_for_testing//file",
+)
+
+py_test(
+ name = "patched_py_wheel_library_test",
+ srcs = [
+ "patched_py_wheel_library_test.py",
+ ],
+ data = [
+ ":patched_extracted_wheel_for_testing",
+ ],
+ deps = [
+ "//python/runfiles",
+ ],
+)
diff --git a/tests/pycross/patched_py_wheel_library_test.py b/tests/pycross/patched_py_wheel_library_test.py
new file mode 100644
index 0000000..4591187
--- /dev/null
+++ b/tests/pycross/patched_py_wheel_library_test.py
@@ -0,0 +1,38 @@
+# 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 pathlib import Path
+
+from python.runfiles import runfiles
+
+RUNFILES = runfiles.Create()
+
+
+class TestPyWheelLibrary(unittest.TestCase):
+ def setUp(self):
+ self.extraction_dir = Path(
+ RUNFILES.Rlocation("rules_python/tests/pycross/patched_extracted_wheel_for_testing")
+ )
+ self.assertTrue(self.extraction_dir.exists(), self.extraction_dir)
+ self.assertTrue(self.extraction_dir.is_dir(), self.extraction_dir)
+
+ def test_patched_file_contents(self):
+ """Validate that the patch got applied correctly."""
+ file = self.extraction_dir / "site-packages/numpy/file_added_via_patch.txt"
+ self.assertEqual(file.read_text(), "Hello from a patch!\n")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pycross/py_wheel_library_test.py b/tests/pycross/py_wheel_library_test.py
new file mode 100644
index 0000000..25d896a
--- /dev/null
+++ b/tests/pycross/py_wheel_library_test.py
@@ -0,0 +1,46 @@
+# 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 pathlib import Path
+
+from python.runfiles import runfiles
+
+RUNFILES = runfiles.Create()
+
+
+class TestPyWheelLibrary(unittest.TestCase):
+ def setUp(self):
+ self.extraction_dir = Path(
+ RUNFILES.Rlocation("rules_python/tests/pycross/extracted_wheel_for_testing")
+ )
+ self.assertTrue(self.extraction_dir.exists(), self.extraction_dir)
+ self.assertTrue(self.extraction_dir.is_dir(), self.extraction_dir)
+
+ def test_file_presence(self):
+ """Validate that the basic file layout looks good."""
+ for path in (
+ "bin/f2py",
+ "site-packages/numpy.libs/libgfortran-daac5196.so.5.0.0",
+ "site-packages/numpy/dtypes.py",
+ "site-packages/numpy/core/_umath_tests.cpython-311-aarch64-linux-gnu.so",
+ ):
+ print(self.extraction_dir / path)
+ self.assertTrue(
+ (self.extraction_dir / path).exists(), f"{path} does not exist"
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/runfiles/BUILD.bazel b/tests/runfiles/BUILD.bazel
index d62e179..6193ee9 100644
--- a/tests/runfiles/BUILD.bazel
+++ b/tests/runfiles/BUILD.bazel
@@ -1,7 +1,11 @@
-load("@rules_python//python:defs.bzl", "py_test")
+load("@rules_python//python:py_test.bzl", "py_test")
+load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
py_test(
name = "runfiles_test",
srcs = ["runfiles_test.py"],
+ env = {
+ "BZLMOD_ENABLED": "1" if BZLMOD_ENABLED else "0",
+ },
deps = ["//python/runfiles"],
)
diff --git a/tests/runfiles/runfiles_test.py b/tests/runfiles/runfiles_test.py
index 3a1f492..03350f3 100644
--- a/tests/runfiles/runfiles_test.py
+++ b/tests/runfiles/runfiles_test.py
@@ -1,4 +1,3 @@
-# pylint: disable=g-bad-file-header
# Copyright 2018 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +15,20 @@
import os
import tempfile
import unittest
+from typing import Any, List, Optional
from python.runfiles import runfiles
class RunfilesTest(unittest.TestCase):
- # """Unit tests for `runfiles.Runfiles`."""
+ """Unit tests for `rules_python.python.runfiles.Runfiles`."""
- def testRlocationArgumentValidation(self):
+ def testRlocationArgumentValidation(self) -> None:
r = runfiles.Create({"RUNFILES_DIR": "whatever"})
- self.assertRaises(ValueError, lambda: r.Rlocation(None))
+ assert r is not None # mypy doesn't understand the unittest api.
+ self.assertRaises(ValueError, lambda: r.Rlocation(None)) # type: ignore
self.assertRaises(ValueError, lambda: r.Rlocation(""))
- self.assertRaises(TypeError, lambda: r.Rlocation(1))
+ self.assertRaises(TypeError, lambda: r.Rlocation(1)) # type: ignore
self.assertRaisesRegex(
ValueError, "is not normalized", lambda: r.Rlocation("../foo")
)
@@ -61,7 +62,7 @@ class RunfilesTest(unittest.TestCase):
lambda: r.Rlocation("\\foo"),
)
- def testCreatesManifestBasedRunfiles(self):
+ def testCreatesManifestBasedRunfiles(self) -> None:
with _MockFile(contents=["a/b c/d"]) as mf:
r = runfiles.Create(
{
@@ -70,10 +71,11 @@ class RunfilesTest(unittest.TestCase):
"TEST_SRCDIR": "always ignored",
}
)
+ assert r is not None # mypy doesn't understand the unittest api.
self.assertEqual(r.Rlocation("a/b"), "c/d")
self.assertIsNone(r.Rlocation("foo"))
- def testManifestBasedRunfilesEnvVars(self):
+ def testManifestBasedRunfilesEnvVars(self) -> None:
with _MockFile(name="MANIFEST") as mf:
r = runfiles.Create(
{
@@ -81,6 +83,7 @@ class RunfilesTest(unittest.TestCase):
"TEST_SRCDIR": "always ignored",
}
)
+ assert r is not None # mypy doesn't understand the unittest api.
self.assertDictEqual(
r.EnvVars(),
{
@@ -97,6 +100,7 @@ class RunfilesTest(unittest.TestCase):
"TEST_SRCDIR": "always ignored",
}
)
+ assert r is not None # mypy doesn't understand the unittest api.
self.assertDictEqual(
r.EnvVars(),
{
@@ -117,6 +121,7 @@ class RunfilesTest(unittest.TestCase):
"TEST_SRCDIR": "always ignored",
}
)
+ assert r is not None # mypy doesn't understand the unittest api.
self.assertDictEqual(
r.EnvVars(),
{
@@ -126,23 +131,25 @@ class RunfilesTest(unittest.TestCase):
},
)
- def testCreatesDirectoryBasedRunfiles(self):
+ def testCreatesDirectoryBasedRunfiles(self) -> None:
r = runfiles.Create(
{
"RUNFILES_DIR": "runfiles/dir",
"TEST_SRCDIR": "always ignored",
}
)
+ assert r is not None # mypy doesn't understand the unittest api.
self.assertEqual(r.Rlocation("a/b"), "runfiles/dir/a/b")
self.assertEqual(r.Rlocation("foo"), "runfiles/dir/foo")
- def testDirectoryBasedRunfilesEnvVars(self):
+ def testDirectoryBasedRunfilesEnvVars(self) -> None:
r = runfiles.Create(
{
"RUNFILES_DIR": "runfiles/dir",
"TEST_SRCDIR": "always ignored",
}
)
+ assert r is not None # mypy doesn't understand the unittest api.
self.assertDictEqual(
r.EnvVars(),
{
@@ -151,13 +158,13 @@ class RunfilesTest(unittest.TestCase):
},
)
- def testFailsToCreateManifestBasedBecauseManifestDoesNotExist(self):
+ def testFailsToCreateManifestBasedBecauseManifestDoesNotExist(self) -> None:
def _Run():
runfiles.Create({"RUNFILES_MANIFEST_FILE": "non-existing path"})
self.assertRaisesRegex(IOError, "non-existing path", _Run)
- def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self):
+ def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self) -> None:
with _MockFile(contents=["a b"]) as mf:
runfiles.Create(
{
@@ -175,7 +182,7 @@ class RunfilesTest(unittest.TestCase):
self.assertIsNone(runfiles.Create({"TEST_SRCDIR": "always ignored"}))
self.assertIsNone(runfiles.Create({"FOO": "bar"}))
- def testManifestBasedRlocation(self):
+ def testManifestBasedRlocation(self) -> None:
with _MockFile(
contents=[
"Foo/runfile1",
@@ -205,7 +212,7 @@ class RunfilesTest(unittest.TestCase):
else:
self.assertEqual(r.Rlocation("/foo"), "/foo")
- def testManifestBasedRlocationWithRepoMappingFromMain(self):
+ def testManifestBasedRlocationWithRepoMappingFromMain(self) -> None:
with _MockFile(
contents=[
",config.json,config.json~1.2.3",
@@ -280,7 +287,7 @@ class RunfilesTest(unittest.TestCase):
self.assertIsNone(r.Rlocation("my_module", ""))
self.assertIsNone(r.Rlocation("protobuf", ""))
- def testManifestBasedRlocationWithRepoMappingFromOtherRepo(self):
+ def testManifestBasedRlocationWithRepoMappingFromOtherRepo(self) -> None:
with _MockFile(
contents=[
",config.json,config.json~1.2.3",
@@ -362,7 +369,7 @@ class RunfilesTest(unittest.TestCase):
self.assertIsNone(r.Rlocation("my_module", "protobuf~3.19.2"))
self.assertIsNone(r.Rlocation("protobuf", "protobuf~3.19.2"))
- def testDirectoryBasedRlocation(self):
+ def testDirectoryBasedRlocation(self) -> None:
# The _DirectoryBased strategy simply joins the runfiles directory and the
# runfile's path on a "/". This strategy does not perform any normalization,
# nor does it check that the path exists.
@@ -374,7 +381,7 @@ class RunfilesTest(unittest.TestCase):
else:
self.assertEqual(r.Rlocation("/foo"), "/foo")
- def testDirectoryBasedRlocationWithRepoMappingFromMain(self):
+ def testDirectoryBasedRlocationWithRepoMappingFromMain(self) -> None:
with _MockFile(
name="_repo_mapping",
contents=[
@@ -441,7 +448,7 @@ class RunfilesTest(unittest.TestCase):
self.assertEqual(r.Rlocation("config.json", ""), dir + "/config.json")
- def testDirectoryBasedRlocationWithRepoMappingFromOtherRepo(self):
+ def testDirectoryBasedRlocationWithRepoMappingFromOtherRepo(self) -> None:
with _MockFile(
name="_repo_mapping",
contents=[
@@ -513,44 +520,49 @@ class RunfilesTest(unittest.TestCase):
r.Rlocation("config.json", "protobuf~3.19.2"), dir + "/config.json"
)
- def testCurrentRepository(self):
- # This test assumes that it is running without --enable_bzlmod as the
- # correct result with Bzlmod would be the empty string - the canonical
- # name # of the main repository. Without Bzlmod, the main repository is
- # treated just like any other repository and has the name of its
- # runfiles directory returned, which coincides with the name specified
- # in the WORKSPACE file.
- #
- # Specify a fake runfiles directory to verify that its value isn't used
- # by the function.
- self.assertEqual(
- runfiles.Create({"RUNFILES_DIR": "whatever"}).CurrentRepository(),
- "rules_python",
- )
+ def testCurrentRepository(self) -> None:
+ # Under bzlmod, the current repository name is the empty string instead
+ # of the name in the workspace file.
+ if bool(int(os.environ["BZLMOD_ENABLED"])):
+ expected = ""
+ else:
+ expected = "rules_python"
+ r = runfiles.Create({"RUNFILES_DIR": "whatever"})
+ assert r is not None # mypy doesn't understand the unittest api.
+ self.assertEqual(r.CurrentRepository(), expected)
@staticmethod
- def IsWindows():
+ def IsWindows() -> bool:
return os.name == "nt"
-class _MockFile(object):
- def __init__(self, name=None, contents=None):
+class _MockFile:
+ def __init__(
+ self, name: Optional[str] = None, contents: Optional[List[Any]] = None
+ ) -> None:
self._contents = contents or []
self._name = name or "x"
- self._path = None
+ self._path: Optional[str] = None
- def __enter__(self):
+ def __enter__(self) -> Any:
tmpdir = os.environ.get("TEST_TMPDIR")
self._path = os.path.join(tempfile.mkdtemp(dir=tmpdir), self._name)
with open(self._path, "wt") as f:
f.writelines(l + "\n" for l in self._contents)
return self
- def __exit__(self, exc_type, exc_value, traceback):
- os.remove(self._path)
- os.rmdir(os.path.dirname(self._path))
-
- def Path(self):
+ def __exit__(
+ self,
+ exc_type: Any, # pylint: disable=unused-argument
+ exc_value: Any, # pylint: disable=unused-argument
+ traceback: Any, # pylint: disable=unused-argument
+ ) -> None:
+ if self._path:
+ os.remove(self._path)
+ os.rmdir(os.path.dirname(self._path))
+
+ def Path(self) -> str:
+ assert self._path is not None
return self._path
diff --git a/tests/support/BUILD.bazel b/tests/support/BUILD.bazel
new file mode 100644
index 0000000..316e9ab
--- /dev/null
+++ b/tests/support/BUILD.bazel
@@ -0,0 +1,39 @@
+# 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.
+
+# ====================
+# NOTE: You probably want to use the constants in test_platforms.bzl
+# Otherwise, you'll probably have to manually call Label() on these targets
+# to force them to resolve in the proper context.
+# ====================
+platform(
+ name = "mac",
+ constraint_values = [
+ "@platforms//os:macos",
+ ],
+)
+
+platform(
+ name = "linux",
+ constraint_values = [
+ "@platforms//os:linux",
+ ],
+)
+
+platform(
+ name = "windows",
+ constraint_values = [
+ "@platforms//os:windows",
+ ],
+)
diff --git a/tests/support/test_platforms.bzl b/tests/support/test_platforms.bzl
new file mode 100644
index 0000000..3ff3c50
--- /dev/null
+++ b/tests/support/test_platforms.bzl
@@ -0,0 +1,20 @@
+# 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.
+"""Constants for referring to platforms."""
+
+# Explicit Label() calls are required so that it resolves in @rules_python
+# context instead of e.g. the @rules_testing context.
+MAC = Label("//tests/support:mac")
+LINUX = Label("//tests/support:linux")
+WINDOWS = Label("//tests/support:windows")
diff --git a/python/tests/toolchains/BUILD.bazel b/tests/toolchains/BUILD.bazel
index 2f804a4..2f804a4 100644
--- a/python/tests/toolchains/BUILD.bazel
+++ b/tests/toolchains/BUILD.bazel
diff --git a/python/tests/toolchains/defs.bzl b/tests/toolchains/defs.bzl
index 653cde6..8776eba 100644
--- a/python/tests/toolchains/defs.bzl
+++ b/tests/toolchains/defs.bzl
@@ -16,6 +16,7 @@
"""
load("//python:versions.bzl", "PLATFORMS", "TOOL_VERSIONS")
+load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
_WINDOWS_RUNNER_TEMPLATE = """\
@ECHO OFF
@@ -24,12 +25,28 @@ powershell.exe -c "& ./{interpreter_path} {run_acceptance_test_py}"
"""
def _acceptance_test_impl(ctx):
- workspace = ctx.actions.declare_file("/".join([ctx.attr.python_version, "WORKSPACE"]))
- ctx.actions.expand_template(
- template = ctx.file._workspace_tmpl,
- output = workspace,
- substitutions = {"%python_version%": ctx.attr.python_version},
- )
+ files = []
+
+ if BZLMOD_ENABLED:
+ module_bazel = ctx.actions.declare_file("/".join([ctx.attr.python_version, "MODULE.bazel"]))
+ ctx.actions.expand_template(
+ template = ctx.file._module_bazel_tmpl,
+ output = module_bazel,
+ substitutions = {"%python_version%": ctx.attr.python_version},
+ )
+ files.append(module_bazel)
+
+ workspace = ctx.actions.declare_file("/".join([ctx.attr.python_version, "WORKSPACE"]))
+ ctx.actions.write(workspace, "")
+ files.append(workspace)
+ else:
+ workspace = ctx.actions.declare_file("/".join([ctx.attr.python_version, "WORKSPACE"]))
+ ctx.actions.expand_template(
+ template = ctx.file._workspace_tmpl,
+ output = workspace,
+ substitutions = {"%python_version%": ctx.attr.python_version},
+ )
+ files.append(workspace)
build_bazel = ctx.actions.declare_file("/".join([ctx.attr.python_version, "BUILD.bazel"]))
ctx.actions.expand_template(
@@ -37,23 +54,27 @@ def _acceptance_test_impl(ctx):
output = build_bazel,
substitutions = {"%python_version%": ctx.attr.python_version},
)
+ files.append(build_bazel)
python_version_test = ctx.actions.declare_file("/".join([ctx.attr.python_version, "python_version_test.py"]))
ctx.actions.symlink(
target_file = ctx.file._python_version_test,
output = python_version_test,
)
+ files.append(python_version_test)
run_acceptance_test_py = ctx.actions.declare_file("/".join([ctx.attr.python_version, "run_acceptance_test.py"]))
ctx.actions.expand_template(
template = ctx.file._run_acceptance_test_tmpl,
output = run_acceptance_test_py,
substitutions = {
+ "%is_bzlmod%": str(BZLMOD_ENABLED),
"%is_windows%": str(ctx.attr.is_windows),
"%python_version%": ctx.attr.python_version,
"%test_location%": "/".join([ctx.attr.test_location, ctx.attr.python_version]),
},
)
+ files.append(run_acceptance_test_py)
toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"]
py3_runtime = toolchain.py3_runtime
@@ -81,14 +102,9 @@ def _acceptance_test_impl(ctx):
),
is_executable = True,
)
+ files.append(executable)
+ files.extend(ctx.files._distribution)
- files = [
- build_bazel,
- executable,
- python_version_test,
- run_acceptance_test_py,
- workspace,
- ] + ctx.files._distribution
return [DefaultInfo(
executable = executable,
files = depset(
@@ -120,26 +136,31 @@ _acceptance_test = rule(
"_build_bazel_tmpl": attr.label(
doc = "The BUILD.bazel template.",
allow_single_file = True,
- default = Label("//python/tests/toolchains/workspace_template:BUILD.bazel.tmpl"),
+ default = Label("//tests/toolchains/workspace_template:BUILD.bazel.tmpl"),
),
"_distribution": attr.label(
doc = "The rules_python source distribution.",
default = Label("//:distribution"),
),
+ "_module_bazel_tmpl": attr.label(
+ doc = "The MODULE.bazel template.",
+ allow_single_file = True,
+ default = Label("//tests/toolchains/workspace_template:MODULE.bazel.tmpl"),
+ ),
"_python_version_test": attr.label(
doc = "The python_version_test.py used to test the Python version.",
allow_single_file = True,
- default = Label("//python/tests/toolchains/workspace_template:python_version_test.py"),
+ default = Label("//tests/toolchains/workspace_template:python_version_test.py"),
),
"_run_acceptance_test_tmpl": attr.label(
doc = "The run_acceptance_test.py template.",
allow_single_file = True,
- default = Label("//python/tests/toolchains:run_acceptance_test.py.tmpl"),
+ default = Label("//tests/toolchains:run_acceptance_test.py.tmpl"),
),
"_workspace_tmpl": attr.label(
doc = "The WORKSPACE template.",
allow_single_file = True,
- default = Label("//python/tests/toolchains/workspace_template:WORKSPACE.tmpl"),
+ default = Label("//tests/toolchains/workspace_template:WORKSPACE.tmpl"),
),
},
test = True,
diff --git a/python/tests/toolchains/run_acceptance_test.py.tmpl b/tests/toolchains/run_acceptance_test.py.tmpl
index 150e1a9..c52e078 100644
--- a/python/tests/toolchains/run_acceptance_test.py.tmpl
+++ b/tests/toolchains/run_acceptance_test.py.tmpl
@@ -15,13 +15,19 @@
import os
import subprocess
import unittest
-
+import pathlib
class TestPythonVersion(unittest.TestCase):
@classmethod
def setUpClass(cls):
os.chdir("%test_location%")
- rules_python_path = os.path.join(os.environ["TEST_SRCDIR"], "rules_python")
+ test_srcdir = os.environ["TEST_SRCDIR"]
+ # When bzlmod is enabled, the name of the directory in runfiles changes
+ # to _main instead of rules_python
+ if os.path.exists(os.path.join(test_srcdir, "_main")):
+ rules_python_path = os.path.join(test_srcdir, "_main")
+ else:
+ rules_python_path = os.path.join(test_srcdir, "rules_python")
test_tmpdir = os.environ["TEST_TMPDIR"]
if %is_windows%:
@@ -43,27 +49,41 @@ class TestPythonVersion(unittest.TestCase):
# * USE_BAZEL_VERSION=/tmp/<something>
os.environ.pop("USE_BAZEL_VERSION", None)
- with open(".bazelrc", "w") as bazelrc:
- bazelrc.write(
- os.linesep.join(
- [
- 'build --override_repository rules_python="{}"'.format(
- rules_python_path.replace("\\", "/")
- ),
- "build --test_output=errors",
- ]
- )
+ bazelrc_lines = [
+ "build --test_output=errors",
+ ]
+
+ if %is_bzlmod%:
+ bazelrc_lines.extend(
+ [
+ 'build --override_module rules_python="{}"'.format(
+ rules_python_path.replace("\\", "/")
+ ),
+ "common --enable_bzlmod",
+ ]
)
+ else:
+ bazelrc_lines.extend(
+ [
+ 'build --override_repository rules_python="{}"'.format(
+ rules_python_path.replace("\\", "/")
+ ),
+ "common --noexperimental_enable_bzlmod",
+ ]
+ )
+
+ bazelrc = pathlib.Path(".bazelrc")
+ bazelrc.write_text(os.linesep.join(bazelrc_lines))
def test_match_toolchain(self):
output = subprocess.check_output(
- f"bazel run @python//:python3 -- --version",
- shell = True, # Shell needed to look up via PATH
- text=True,
+ f"bazel run --announce_rc @python//:python3 -- --version",
+ shell = True, # Shell needed to look up via PATH
+ text=True,
).strip()
self.assertEqual(output, "Python %python_version%")
- subprocess.run("bazel test //...", shell=True, check=True)
+ subprocess.run("bazel test --announce_rc //...", shell=True, check=True)
if __name__ == "__main__":
diff --git a/python/tests/toolchains/versions_test.bzl b/tests/toolchains/versions_test.bzl
index b885d22..b885d22 100644
--- a/python/tests/toolchains/versions_test.bzl
+++ b/tests/toolchains/versions_test.bzl
diff --git a/python/tests/toolchains/workspace_template/BUILD.bazel b/tests/toolchains/workspace_template/BUILD.bazel
index dd70844..7f3e7b0 100644
--- a/python/tests/toolchains/workspace_template/BUILD.bazel
+++ b/tests/toolchains/workspace_template/BUILD.bazel
@@ -1,5 +1,6 @@
exports_files([
"BUILD.bazel.tmpl",
+ "MODULE.bazel.tmpl",
"WORKSPACE.tmpl",
"python_version_test.py",
])
diff --git a/python/tests/toolchains/workspace_template/BUILD.bazel.tmpl b/tests/toolchains/workspace_template/BUILD.bazel.tmpl
index 4a45209..4a45209 100644
--- a/python/tests/toolchains/workspace_template/BUILD.bazel.tmpl
+++ b/tests/toolchains/workspace_template/BUILD.bazel.tmpl
diff --git a/tests/toolchains/workspace_template/MODULE.bazel.tmpl b/tests/toolchains/workspace_template/MODULE.bazel.tmpl
new file mode 100644
index 0000000..9e3a844
--- /dev/null
+++ b/tests/toolchains/workspace_template/MODULE.bazel.tmpl
@@ -0,0 +1,19 @@
+module(
+ name = "module_test",
+ version = "0.0.0",
+ compatibility_level = 1,
+)
+
+bazel_dep(name = "bazel_skylib", version = "1.3.0")
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+ module_name = "rules_python",
+ path = "",
+)
+
+python = use_extension("@rules_python//python/extensions:python.bzl", "python")
+python.toolchain(
+ is_default = True,
+ python_version = "%python_version%",
+)
+use_repo(python, "python_versions", python = "python_%python_version%".replace(".", "_"))
diff --git a/python/tests/toolchains/workspace_template/README.md b/tests/toolchains/workspace_template/README.md
index b4d6e6a..b4d6e6a 100644
--- a/python/tests/toolchains/workspace_template/README.md
+++ b/tests/toolchains/workspace_template/README.md
diff --git a/python/tests/toolchains/workspace_template/WORKSPACE.tmpl b/tests/toolchains/workspace_template/WORKSPACE.tmpl
index 973e020..3335f4b 100644
--- a/python/tests/toolchains/workspace_template/WORKSPACE.tmpl
+++ b/tests/toolchains/workspace_template/WORKSPACE.tmpl
@@ -19,7 +19,9 @@ local_repository(
path = "",
)
-load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+load("@rules_python//python:repositories.bzl", "python_register_toolchains", "py_repositories")
+
+py_repositories()
python_register_toolchains(
name = "python",
diff --git a/python/tests/toolchains/workspace_template/python_version_test.py b/tests/toolchains/workspace_template/python_version_test.py
index c82611c..c82611c 100644
--- a/python/tests/toolchains/workspace_template/python_version_test.py
+++ b/tests/toolchains/workspace_template/python_version_test.py
diff --git a/third_party/rules_pycross/LICENSE b/third_party/rules_pycross/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/third_party/rules_pycross/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/third_party/rules_pycross/pycross/private/BUILD.bazel b/third_party/rules_pycross/pycross/private/BUILD.bazel
new file mode 100644
index 0000000..f59b087
--- /dev/null
+++ b/third_party/rules_pycross/pycross/private/BUILD.bazel
@@ -0,0 +1,14 @@
+# Copyright 2023 Jeremy Volkman. All rights reserved.
+# 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.
diff --git a/third_party/rules_pycross/pycross/private/providers.bzl b/third_party/rules_pycross/pycross/private/providers.bzl
new file mode 100644
index 0000000..47fc9f7
--- /dev/null
+++ b/third_party/rules_pycross/pycross/private/providers.bzl
@@ -0,0 +1,32 @@
+# Copyright 2023 Jeremy Volkman. All rights reserved.
+# 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 providers."""
+
+PyWheelInfo = provider(
+ doc = "Information about a Python wheel.",
+ fields = {
+ "name_file": "File: A file containing the canonical name of the wheel.",
+ "wheel_file": "File: The wheel file itself.",
+ },
+)
+
+PyTargetEnvironmentInfo = provider(
+ doc = "A target environment description.",
+ fields = {
+ "file": "The JSON file containing target environment information.",
+ "python_compatible_with": "A list of constraints used to select this platform.",
+ },
+)
diff --git a/third_party/rules_pycross/pycross/private/tools/BUILD.bazel b/third_party/rules_pycross/pycross/private/tools/BUILD.bazel
new file mode 100644
index 0000000..a87e6aa
--- /dev/null
+++ b/third_party/rules_pycross/pycross/private/tools/BUILD.bazel
@@ -0,0 +1,26 @@
+# Copyright 2023 Jeremy Volkman. All rights reserved.
+# 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.
+
+load("//python:defs.bzl", "py_binary")
+
+py_binary(
+ name = "wheel_installer",
+ srcs = ["wheel_installer.py"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//python/pip_install/tools/wheel_installer:lib",
+ "@pypi__installer//:lib",
+ ],
+)
diff --git a/third_party/rules_pycross/pycross/private/tools/wheel_installer.py b/third_party/rules_pycross/pycross/private/tools/wheel_installer.py
new file mode 100644
index 0000000..0c352cf
--- /dev/null
+++ b/third_party/rules_pycross/pycross/private/tools/wheel_installer.py
@@ -0,0 +1,196 @@
+# Copyright 2023 Jeremy Volkman. All rights reserved.
+# 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.
+
+"""
+A tool that invokes pypa/build to build the given sdist tarball.
+"""
+
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+from pathlib import Path
+from typing import Any
+
+from installer import install
+from installer.destinations import SchemeDictionaryDestination
+from installer.sources import WheelFile
+
+from python.pip_install.tools.wheel_installer import namespace_pkgs
+
+
+def setup_namespace_pkg_compatibility(wheel_dir: Path) -> None:
+ """Converts native namespace packages to pkgutil-style packages
+
+ Namespace packages can be created in one of three ways. They are detailed here:
+ https://packaging.python.org/guides/packaging-namespace-packages/#creating-a-namespace-package
+
+ 'pkgutil-style namespace packages' (2) and 'pkg_resources-style namespace packages' (3) works in Bazel, but
+ 'native namespace packages' (1) do not.
+
+ We ensure compatibility with Bazel of method 1 by converting them into method 2.
+
+ Args:
+ wheel_dir: the directory of the wheel to convert
+ """
+
+ namespace_pkg_dirs = namespace_pkgs.implicit_namespace_packages(
+ str(wheel_dir),
+ ignored_dirnames=["%s/bin" % wheel_dir],
+ )
+
+ for ns_pkg_dir in namespace_pkg_dirs:
+ namespace_pkgs.add_pkgutil_style_namespace_pkg_init(ns_pkg_dir)
+
+
+def main(args: Any) -> None:
+ dest_dir = args.directory
+ lib_dir = dest_dir / "site-packages"
+ destination = SchemeDictionaryDestination(
+ scheme_dict={
+ "platlib": str(lib_dir),
+ "purelib": str(lib_dir),
+ "headers": str(dest_dir / "include"),
+ "scripts": str(dest_dir / "bin"),
+ "data": str(dest_dir / "data"),
+ },
+ interpreter="/usr/bin/env python3", # Generic; it's not feasible to run these scripts directly.
+ script_kind="posix",
+ bytecode_optimization_levels=[0, 1],
+ )
+
+ link_dir = Path(tempfile.mkdtemp())
+ if args.wheel_name_file:
+ with open(args.wheel_name_file, "r") as f:
+ wheel_name = f.read().strip()
+ else:
+ wheel_name = os.path.basename(args.wheel)
+
+ link_path = link_dir / wheel_name
+ os.symlink(os.path.join(os.getcwd(), args.wheel), link_path)
+
+ try:
+ with WheelFile.open(link_path) as source:
+ install(
+ source=source,
+ destination=destination,
+ # Additional metadata that is generated by the installation tool.
+ additional_metadata={
+ "INSTALLER": b"https://github.com/bazelbuild/rules_python/tree/main/third_party/rules_pycross",
+ },
+ )
+ finally:
+ shutil.rmtree(link_dir, ignore_errors=True)
+
+ setup_namespace_pkg_compatibility(lib_dir)
+
+ if args.patch:
+ if not args.patch_tool and not args.patch_tool_target:
+ raise ValueError("Specify one of 'patch_tool' or 'patch_tool_target'.")
+
+ patch_args = [
+ args.patch_tool or Path.cwd() / args.patch_tool_target
+ ] + args.patch_arg
+ for patch in args.patch:
+ with patch.open("r") as stdin:
+ try:
+ subprocess.run(
+ patch_args,
+ stdin=stdin,
+ check=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ cwd=args.directory,
+ )
+ except subprocess.CalledProcessError as error:
+ print(f"Patch {patch} failed to apply:")
+ print(error.stdout.decode("utf-8"))
+ raise
+
+
+def parse_flags(argv) -> Any:
+ parser = argparse.ArgumentParser(description="Extract a Python wheel.")
+
+ parser.add_argument(
+ "--wheel",
+ type=Path,
+ required=True,
+ help="The wheel file path.",
+ )
+
+ parser.add_argument(
+ "--wheel-name-file",
+ type=Path,
+ required=False,
+ help="A file containing the canonical name of the wheel.",
+ )
+
+ parser.add_argument(
+ "--enable-implicit-namespace-pkgs",
+ action="store_true",
+ help="If true, disables conversion of implicit namespace packages and will unzip as-is.",
+ )
+
+ parser.add_argument(
+ "--directory",
+ type=Path,
+ help="The output path.",
+ )
+
+ parser.add_argument(
+ "--patch",
+ type=Path,
+ default=[],
+ action="append",
+ help="A patch file to apply.",
+ )
+
+ parser.add_argument(
+ "--patch-arg",
+ type=str,
+ default=[],
+ action="append",
+ help="An argument for the patch tool when applying the patches.",
+ )
+
+ parser.add_argument(
+ "--patch-tool",
+ type=str,
+ help=(
+ "The tool from PATH to invoke when applying patches. "
+ "If set, --patch-tool-target is ignored."
+ ),
+ )
+
+ parser.add_argument(
+ "--patch-tool-target",
+ type=Path,
+ help=(
+ "The path to the tool to invoke when applying patches. "
+ "Ignored when --patch-tool is set."
+ ),
+ )
+
+ return parser.parse_args(argv[1:])
+
+
+if __name__ == "__main__":
+ # When under `bazel run`, change to the actual working dir.
+ if "BUILD_WORKING_DIRECTORY" in os.environ:
+ os.chdir(os.environ["BUILD_WORKING_DIRECTORY"])
+
+ main(parse_flags(sys.argv))
diff --git a/third_party/rules_pycross/pycross/private/wheel_library.bzl b/third_party/rules_pycross/pycross/private/wheel_library.bzl
new file mode 100644
index 0000000..166e1d0
--- /dev/null
+++ b/third_party/rules_pycross/pycross/private/wheel_library.bzl
@@ -0,0 +1,174 @@
+# Copyright 2023 Jeremy Volkman. All rights reserved.
+# 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.
+
+"""Implementation of the py_wheel_library rule."""
+
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load("//python:defs.bzl", "PyInfo")
+load(":providers.bzl", "PyWheelInfo")
+
+def _py_wheel_library_impl(ctx):
+ out = ctx.actions.declare_directory(ctx.attr.name)
+
+ wheel_target = ctx.attr.wheel
+ if PyWheelInfo in wheel_target:
+ wheel_file = wheel_target[PyWheelInfo].wheel_file
+ name_file = wheel_target[PyWheelInfo].name_file
+ else:
+ wheel_file = ctx.file.wheel
+ name_file = None
+
+ args = ctx.actions.args().use_param_file("--flagfile=%s")
+ args.add("--wheel", wheel_file)
+ args.add("--directory", out.path)
+ args.add_all(ctx.files.patches, format_each = "--patch=%s")
+ args.add_all(ctx.attr.patch_args, format_each = "--patch-arg=%s")
+ args.add("--patch-tool", ctx.attr.patch_tool)
+
+ tools = []
+ inputs = [wheel_file] + ctx.files.patches
+ if name_file:
+ inputs.append(name_file)
+ args.add("--wheel-name-file", name_file)
+
+ if ctx.attr.patch_tool_target:
+ args.add("--patch-tool-target", ctx.attr.patch_tool_target.files_to_run.executable)
+ tools.append(ctx.executable.patch_tool_target)
+
+ if ctx.attr.enable_implicit_namespace_pkgs:
+ args.add("--enable-implicit-namespace-pkgs")
+
+ # We apply patches in the same action as the extraction to minimize the
+ # number of times we cache the wheel contents. If we were to split this
+ # into 2 actions, then the wheel contents would be cached twice.
+ ctx.actions.run(
+ inputs = inputs,
+ outputs = [out],
+ executable = ctx.executable._tool,
+ tools = tools,
+ arguments = [args],
+ # Set environment variables to make generated .pyc files reproducible.
+ env = {
+ "PYTHONHASHSEED": "0",
+ "SOURCE_DATE_EPOCH": "315532800",
+ },
+ mnemonic = "WheelInstall",
+ progress_message = "Installing %s" % ctx.file.wheel.basename,
+ )
+
+ has_py2_only_sources = ctx.attr.python_version == "PY2"
+ has_py3_only_sources = ctx.attr.python_version == "PY3"
+ if not has_py2_only_sources:
+ for d in ctx.attr.deps:
+ if d[PyInfo].has_py2_only_sources:
+ has_py2_only_sources = True
+ break
+ if not has_py3_only_sources:
+ for d in ctx.attr.deps:
+ if d[PyInfo].has_py3_only_sources:
+ has_py3_only_sources = True
+ break
+
+ # TODO: Is there a more correct way to get this runfiles-relative import path?
+ imp = paths.join(
+ ctx.label.workspace_name or ctx.workspace_name, # Default to the local workspace.
+ ctx.label.package,
+ ctx.label.name,
+ "site-packages", # we put lib files in this subdirectory.
+ )
+
+ imports = depset(
+ direct = [imp],
+ transitive = [d[PyInfo].imports for d in ctx.attr.deps],
+ )
+ transitive_sources = depset(
+ direct = [out],
+ transitive = [dep[PyInfo].transitive_sources for dep in ctx.attr.deps if PyInfo in dep],
+ )
+ runfiles = ctx.runfiles(files = [out])
+ for d in ctx.attr.deps:
+ runfiles = runfiles.merge(d[DefaultInfo].default_runfiles)
+
+ return [
+ DefaultInfo(
+ files = depset(direct = [out]),
+ runfiles = runfiles,
+ ),
+ PyInfo(
+ has_py2_only_sources = has_py2_only_sources,
+ has_py3_only_sources = has_py3_only_sources,
+ imports = imports,
+ transitive_sources = transitive_sources,
+ uses_shared_libraries = True, # Docs say this is unused
+ ),
+ ]
+
+py_wheel_library = rule(
+ implementation = _py_wheel_library_impl,
+ attrs = {
+ "deps": attr.label_list(
+ doc = "A list of this wheel's Python library dependencies.",
+ providers = [DefaultInfo, PyInfo],
+ ),
+ "enable_implicit_namespace_pkgs": attr.bool(
+ default = True,
+ doc = """
+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.
+ """,
+ ),
+ "patch_args": attr.string_list(
+ default = ["-p0"],
+ doc =
+ "The arguments given to the patch tool. Defaults to -p0, " +
+ "however -p1 will usually be needed for patches generated by " +
+ "git. If multiple -p arguments are specified, the last one will take effect.",
+ ),
+ "patch_tool": attr.string(
+ doc = "The patch(1) utility from the host to use. " +
+ "If set, overrides `patch_tool_target`. Please note that setting " +
+ "this means that builds are not completely hermetic.",
+ ),
+ "patch_tool_target": attr.label(
+ executable = True,
+ cfg = "exec",
+ doc = "The label of the patch(1) utility to use. " +
+ "Only used if `patch_tool` is not set.",
+ ),
+ "patches": attr.label_list(
+ allow_files = True,
+ default = [],
+ doc =
+ "A list of files that are to be applied as patches after " +
+ "extracting the archive. This will use the patch command line tool.",
+ ),
+ "python_version": attr.string(
+ doc = "The python version required for this wheel ('PY2' or 'PY3')",
+ values = ["PY2", "PY3", ""],
+ ),
+ "wheel": attr.label(
+ doc = "The wheel file.",
+ allow_single_file = [".whl"],
+ mandatory = True,
+ ),
+ "_tool": attr.label(
+ default = Label("//third_party/rules_pycross/pycross/private/tools:wheel_installer"),
+ cfg = "exec",
+ executable = True,
+ ),
+ },
+)
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
index fd951d9..51bd56d 100644
--- a/tools/BUILD.bazel
+++ b/tools/BUILD.bazel
@@ -21,6 +21,7 @@ licenses(["notice"])
py_binary(
name = "wheelmaker",
srcs = ["wheelmaker.py"],
+ deps = ["@pypi__packaging//:lib"],
)
filegroup(
diff --git a/tools/bazel_integration_test/BUILD.bazel b/tools/bazel_integration_test/BUILD.bazel
deleted file mode 100644
index 10566c4..0000000
--- a/tools/bazel_integration_test/BUILD.bazel
+++ /dev/null
@@ -1 +0,0 @@
-exports_files(["test_runner.py"])
diff --git a/tools/bazel_integration_test/bazel_integration_test.bzl b/tools/bazel_integration_test/bazel_integration_test.bzl
deleted file mode 100644
index c016551..0000000
--- a/tools/bazel_integration_test/bazel_integration_test.bzl
+++ /dev/null
@@ -1,134 +0,0 @@
-# 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.
-
-"Define a rule for running bazel test under Bazel"
-
-load("//:version.bzl", "SUPPORTED_BAZEL_VERSIONS", "bazel_version_to_binary_label")
-load("//python:defs.bzl", "py_test")
-
-BAZEL_BINARY = bazel_version_to_binary_label(SUPPORTED_BAZEL_VERSIONS[0])
-
-_ATTRS = {
- "bazel_binary": attr.label(
- default = BAZEL_BINARY,
- doc = """The bazel binary files to test against.
-
-It is assumed by the test runner that the bazel binary is found at label_workspace/bazel (wksp/bazel.exe on Windows)""",
- ),
- "bazel_commands": attr.string_list(
- default = ["info", "test --test_output=errors ..."],
- doc = """The list of bazel commands to run.
-
-Note that if a command contains a bare `--` argument, the --test_arg passed to Bazel will appear before it.
-""",
- ),
- "bzlmod": attr.bool(
- default = False,
- doc = """Whether the test uses bzlmod.""",
- ),
- "workspace_files": attr.label(
- doc = """A filegroup of all files in the workspace-under-test necessary to run the test.""",
- ),
-}
-
-def _config_impl(ctx):
- if len(SUPPORTED_BAZEL_VERSIONS) > 1:
- fail("""
- bazel_integration_test doesn't support multiple Bazel versions to test against yet.
- """)
- if len(ctx.files.workspace_files) == 0:
- fail("""
-No files were found to run under integration testing. See comment in /.bazelrc.
-You probably need to run
- tools/bazel_integration_test/update_deleted_packages.sh
-""")
-
- # Serialize configuration file for test runner
- config = ctx.actions.declare_file("%s.json" % ctx.attr.name)
- ctx.actions.write(
- output = config,
- content = """
-{{
- "workspaceRoot": "{TMPL_workspace_root}",
- "bazelBinaryWorkspace": "{TMPL_bazel_binary_workspace}",
- "bazelCommands": [ {TMPL_bazel_commands} ],
- "bzlmod": {TMPL_bzlmod}
-}}
-""".format(
- TMPL_workspace_root = ctx.files.workspace_files[0].dirname,
- TMPL_bazel_binary_workspace = ctx.attr.bazel_binary.label.workspace_name,
- TMPL_bazel_commands = ", ".join(["\"%s\"" % s for s in ctx.attr.bazel_commands]),
- TMPL_bzlmod = str(ctx.attr.bzlmod).lower(),
- ),
- )
-
- return [DefaultInfo(
- files = depset([config]),
- runfiles = ctx.runfiles(files = [config]),
- )]
-
-_config = rule(
- implementation = _config_impl,
- doc = "Configures an integration test that runs a specified version of bazel against an external workspace.",
- attrs = _ATTRS,
-)
-
-def bazel_integration_test(name, override_bazel_version = None, bzlmod = False, dirname = None, **kwargs):
- """Wrapper macro to set default srcs and run a py_test with config
-
- Args:
- name: name of the resulting py_test
- override_bazel_version: bazel version to use in test
- bzlmod: whether the test uses bzlmod
- dirname: the directory name of the test. Defaults to value of `name` after trimming the `_example` suffix.
- **kwargs: additional attributes like timeout and visibility
- """
-
- # By default, we assume sources for "pip_example" are in examples/pip/**/*
- dirname = dirname or name[:-len("_example")]
- native.filegroup(
- name = "_%s_sources" % name,
- srcs = native.glob(
- ["%s/**/*" % dirname],
- exclude = ["%s/bazel-*/**" % dirname],
- ),
- )
- workspace_files = kwargs.pop("workspace_files", "_%s_sources" % name)
-
- bazel_binary = BAZEL_BINARY if not override_bazel_version else bazel_version_to_binary_label(override_bazel_version)
- _config(
- name = "_%s_config" % name,
- workspace_files = workspace_files,
- bazel_binary = bazel_binary,
- bzlmod = bzlmod,
- )
-
- tags = kwargs.pop("tags", [])
- tags.append("integration-test")
-
- py_test(
- name = name,
- srcs = [Label("//tools/bazel_integration_test:test_runner.py")],
- main = "test_runner.py",
- args = [native.package_name() + "/_%s_config.json" % name],
- deps = [Label("//python/runfiles")],
- data = [
- bazel_binary,
- "//:distribution",
- "_%s_config" % name,
- workspace_files,
- ],
- tags = tags,
- **kwargs
- )
diff --git a/tools/bazel_integration_test/test_runner.py b/tools/bazel_integration_test/test_runner.py
deleted file mode 100644
index 3940e87..0000000
--- a/tools/bazel_integration_test/test_runner.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# 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 json
-import os
-import platform
-import re
-import shutil
-import sys
-import tempfile
-import textwrap
-from pathlib import Path
-from subprocess import Popen
-
-from rules_python.python.runfiles import runfiles
-
-r = runfiles.Create()
-
-
-def main(conf_file):
- with open(conf_file) as j:
- config = json.load(j)
-
- isWindows = platform.system() == "Windows"
- bazelBinary = r.Rlocation(
- os.path.join(
- config["bazelBinaryWorkspace"], "bazel.exe" if isWindows else "bazel"
- )
- )
-
- workspacePath = config["workspaceRoot"]
- # Canonicalize bazel external/some_repo/foo
- if workspacePath.startswith("external/"):
- workspacePath = ".." + workspacePath[len("external") :]
-
- with tempfile.TemporaryDirectory(dir=os.environ["TEST_TMPDIR"]) as tmp_homedir:
- home_bazel_rc = Path(tmp_homedir) / ".bazelrc"
- home_bazel_rc.write_text(
- textwrap.dedent(
- """\
- startup --max_idle_secs=1
- common --announce_rc
- """
- )
- )
-
- with tempfile.TemporaryDirectory(dir=os.environ["TEST_TMPDIR"]) as tmpdir:
- workdir = os.path.join(tmpdir, "wksp")
- print("copying workspace under test %s to %s" % (workspacePath, workdir))
- shutil.copytree(workspacePath, workdir)
-
- for command in config["bazelCommands"]:
- bazel_args = command.split(" ")
- bazel_args.append(
- "--override_repository=rules_python=%s/rules_python"
- % os.environ["TEST_SRCDIR"]
- )
- bazel_args.append(
- "--override_repository=rules_python_gazelle_plugin=%s/rules_python_gazelle_plugin"
- % os.environ["TEST_SRCDIR"]
- )
-
- # TODO: --override_module isn't supported in the current BAZEL_VERSION (5.2.0)
- # This condition and attribute can be removed when bazel is updated for
- # the rest of rules_python.
- if config["bzlmod"]:
- bazel_args.append(
- "--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
- os.environ["HOME"] = str(tmp_homedir)
-
- bazel_args.insert(0, bazelBinary)
- bazel_process = Popen(bazel_args, cwd=workdir)
- bazel_process.wait()
- error = bazel_process.returncode != 0
-
- if platform.system() == "Windows":
- # Cleanup any bazel files
- bazel_process = Popen([bazelBinary, "clean"], cwd=workdir)
- bazel_process.wait()
- error |= bazel_process.returncode != 0
-
- # Shutdown the bazel instance to avoid issues cleaning up the workspace
- bazel_process = Popen([bazelBinary, "shutdown"], cwd=workdir)
- bazel_process.wait()
- error |= bazel_process.returncode != 0
-
- if error != 0:
- # Test failure in Bazel is exit 3
- # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44
- sys.exit(3)
-
-
-if __name__ == "__main__":
- main(sys.argv[1])
diff --git a/tools/build_defs/python/private/BUILD.bazel b/tools/build_defs/python/private/BUILD.bazel
new file mode 100644
index 0000000..0a7f308
--- /dev/null
+++ b/tools/build_defs/python/private/BUILD.bazel
@@ -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.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+ visibility = ["//python:__subpackages__"],
+)
+
+bzl_library(
+ name = "py_internal_renamed_bzl",
+ srcs = ["py_internal_renamed.bzl"],
+ visibility = ["@rules_python_internal//:__subpackages__"],
+)
diff --git a/tools/build_defs/python/private/py_internal_renamed.bzl b/tools/build_defs/python/private/py_internal_renamed.bzl
new file mode 100644
index 0000000..a12fc2d
--- /dev/null
+++ b/tools/build_defs/python/private/py_internal_renamed.bzl
@@ -0,0 +1,30 @@
+# 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 RULE IMPLEMENTATION ONLY: Do not use outside of the rule implementations and their tests.
+
+NOTE: This file is only loaded by @rules_python_internal//:py_internal.bzl. This
+is because the `py_internal` global symbol is only present in Bazel 7+, so
+a repo rule has to conditionally load this depending on the Bazel version.
+
+Re-exports the restricted-use py_internal helper under another name. This is
+necessary because `py_internal = py_internal` results in an error (trying
+to bind a local symbol to itself before its defined).
+
+This is to allow the rule implementation in the //python directory to access
+the internal helpers only rules_python is allowed to use.
+
+These may change at any time and are closely coupled to the rule implementation.
+"""
+
+py_internal_renamed = py_internal
diff --git a/tools/private/update_deps/BUILD.bazel b/tools/private/update_deps/BUILD.bazel
new file mode 100644
index 0000000..2ab7cc7
--- /dev/null
+++ b/tools/private/update_deps/BUILD.bazel
@@ -0,0 +1,76 @@
+# 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.
+load("//python:py_binary.bzl", "py_binary")
+load("//python:py_library.bzl", "py_library")
+load("//python:py_test.bzl", "py_test")
+
+licenses(["notice"])
+
+py_library(
+ name = "args",
+ srcs = ["args.py"],
+ imports = ["../../.."],
+ deps = ["//python/runfiles"],
+)
+
+py_library(
+ name = "update_file",
+ srcs = ["update_file.py"],
+ imports = ["../../.."],
+)
+
+py_binary(
+ name = "update_coverage_deps",
+ srcs = ["update_coverage_deps.py"],
+ data = [
+ "//python/private:coverage_deps",
+ ],
+ env = {
+ "UPDATE_FILE": "$(rlocationpath //python/private:coverage_deps)",
+ },
+ imports = ["../../.."],
+ deps = [
+ ":args",
+ ":update_file",
+ ],
+)
+
+py_binary(
+ name = "update_pip_deps",
+ srcs = ["update_pip_deps.py"],
+ data = [
+ "//:MODULE.bazel",
+ "//python/pip_install:repositories",
+ "//python/pip_install:requirements_txt",
+ ],
+ env = {
+ "MODULE_BAZEL": "$(rlocationpath //:MODULE.bazel)",
+ "REPOSITORIES_BZL": "$(rlocationpath //python/pip_install:repositories)",
+ "REQUIREMENTS_TXT": "$(rlocationpath //python/pip_install:requirements_txt)",
+ },
+ imports = ["../../.."],
+ deps = [
+ ":args",
+ ":update_file",
+ ],
+)
+
+py_test(
+ name = "update_file_test",
+ srcs = ["update_file_test.py"],
+ imports = ["../../.."],
+ deps = [
+ ":update_file",
+ ],
+)
diff --git a/tools/private/update_deps/args.py b/tools/private/update_deps/args.py
new file mode 100644
index 0000000..293294c
--- /dev/null
+++ b/tools/private/update_deps/args.py
@@ -0,0 +1,35 @@
+# 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.
+
+"""A small library for common arguments when updating files."""
+
+import pathlib
+
+from python.runfiles import runfiles
+
+
+def path_from_runfiles(input: str) -> pathlib.Path:
+ """A helper to create a path from runfiles.
+
+ Args:
+ input: the string input to construct a path.
+
+ Returns:
+ the pathlib.Path path to a file which is verified to exist.
+ """
+ path = pathlib.Path(runfiles.Create().Rlocation(input))
+ if not path.exists():
+ raise ValueError(f"Path '{path}' does not exist")
+
+ return path
diff --git a/tools/update_coverage_deps.py b/tools/private/update_deps/update_coverage_deps.py
index 57b7850..6152d70 100755
--- a/tools/update_coverage_deps.py
+++ b/tools/private/update_deps/update_coverage_deps.py
@@ -22,6 +22,7 @@ We are not running this with 'bazel run' to keep the dependencies minimal
import argparse
import difflib
import json
+import os
import pathlib
import sys
import textwrap
@@ -30,6 +31,9 @@ from dataclasses import dataclass
from typing import Any
from urllib import request
+from tools.private.update_deps.args import path_from_runfiles
+from tools.private.update_deps.update_file import update_file
+
# This should be kept in sync with //python:versions.bzl
_supported_platforms = {
# Windows is unsupported right now
@@ -110,64 +114,6 @@ def _map(
)
-def _writelines(path: pathlib.Path, lines: list[str]):
- with open(path, "w") as f:
- f.writelines(lines)
-
-
-def _difflines(path: pathlib.Path, lines: list[str]):
- with open(path) as f:
- input = f.readlines()
-
- rules_python = pathlib.Path(__file__).parent.parent
- p = path.relative_to(rules_python)
-
- print(f"Diff of the changes that would be made to '{p}':")
- for line in difflib.unified_diff(
- input,
- lines,
- fromfile=f"a/{p}",
- tofile=f"b/{p}",
- ):
- print(line, end="")
-
- # Add an empty line at the end of the diff
- print()
-
-
-def _update_file(
- path: pathlib.Path,
- snippet: str,
- start_marker: str,
- end_marker: str,
- dry_run: bool = True,
-):
- with open(path) as f:
- input = f.readlines()
-
- out = []
- skip = False
- for line in input:
- if skip:
- if not line.startswith(end_marker):
- continue
-
- skip = False
-
- out.append(line)
-
- if not line.startswith(start_marker):
- continue
-
- skip = True
- out.extend([f"{line}\n" for line in snippet.splitlines()])
-
- if dry_run:
- _difflines(path, out)
- else:
- _writelines(path, out)
-
-
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(__doc__)
parser.add_argument(
@@ -193,13 +139,19 @@ def _parse_args() -> argparse.Namespace:
action="store_true",
help="Wether to write to files",
)
+ parser.add_argument(
+ "--update-file",
+ type=path_from_runfiles,
+ default=os.environ.get("UPDATE_FILE"),
+ help="The path for the file to be updated, defaults to the value taken from UPDATE_FILE",
+ )
return parser.parse_args()
def main():
args = _parse_args()
- api_url = f"https://pypi.python.org/pypi/{args.name}/{args.version}/json"
+ api_url = f"https://pypi.org/pypi/{args.name}/{args.version}/json"
req = request.Request(api_url)
with request.urlopen(req) as response:
data = json.loads(response.read().decode("utf-8"))
@@ -230,14 +182,12 @@ def main():
urls.sort(key=lambda x: f"{x.python}_{x.platform}")
- rules_python = pathlib.Path(__file__).parent.parent
-
# Update the coverage_deps, which are used to register deps
- _update_file(
- path=rules_python / "python" / "private" / "coverage_deps.bzl",
+ update_file(
+ path=args.update_file,
snippet=f"_coverage_deps = {repr(Deps(urls))}\n",
- start_marker="#START: managed by update_coverage_deps.py script",
- end_marker="#END: managed by update_coverage_deps.py script",
+ start_marker="# START: maintained by 'bazel run //tools/private:update_coverage_deps'",
+ end_marker="# END: maintained by 'bazel run //tools/private:update_coverage_deps'",
dry_run=args.dry_run,
)
diff --git a/tools/private/update_deps/update_file.py b/tools/private/update_deps/update_file.py
new file mode 100644
index 0000000..ab3e8a8
--- /dev/null
+++ b/tools/private/update_deps/update_file.py
@@ -0,0 +1,114 @@
+# 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.
+
+"""A small library to update bazel files within the repo.
+
+This is reused in other files updating coverage deps and pip deps.
+"""
+
+import argparse
+import difflib
+import pathlib
+import sys
+
+
+def _writelines(path: pathlib.Path, out: str):
+ with open(path, "w") as f:
+ f.write(out)
+
+
+def unified_diff(name: str, a: str, b: str) -> str:
+ return "".join(
+ difflib.unified_diff(
+ a.splitlines(keepends=True),
+ b.splitlines(keepends=True),
+ fromfile=f"a/{name}",
+ tofile=f"b/{name}",
+ )
+ ).strip()
+
+
+def replace_snippet(
+ current: str,
+ snippet: str,
+ start_marker: str,
+ end_marker: str,
+) -> str:
+ """Update a file on disk to replace text in a file between two markers.
+
+ Args:
+ path: pathlib.Path, the path to the file to be modified.
+ snippet: str, the snippet of code to insert between the markers.
+ start_marker: str, the text that marks the start of the region to be replaced.
+ end_markr: str, the text that marks the end of the region to be replaced.
+ dry_run: bool, if set to True, then the file will not be written and instead we are going to print a diff to
+ stdout.
+ """
+ lines = []
+ skip = False
+ found_match = False
+ for line in current.splitlines(keepends=True):
+ if line.lstrip().startswith(start_marker.lstrip()):
+ found_match = True
+ lines.append(line)
+ lines.append(snippet.rstrip() + "\n")
+ skip = True
+ elif skip and line.lstrip().startswith(end_marker):
+ skip = False
+ lines.append(line)
+ continue
+ elif not skip:
+ lines.append(line)
+
+ if not found_match:
+ raise RuntimeError(f"Start marker '{start_marker}' was not found")
+ if skip:
+ raise RuntimeError(f"End marker '{end_marker}' was not found")
+
+ return "".join(lines)
+
+
+def update_file(
+ path: pathlib.Path,
+ snippet: str,
+ start_marker: str,
+ end_marker: str,
+ dry_run: bool = True,
+):
+ """update a file on disk to replace text in a file between two markers.
+
+ Args:
+ path: pathlib.Path, the path to the file to be modified.
+ snippet: str, the snippet of code to insert between the markers.
+ start_marker: str, the text that marks the start of the region to be replaced.
+ end_markr: str, the text that marks the end of the region to be replaced.
+ dry_run: bool, if set to True, then the file will not be written and instead we are going to print a diff to
+ stdout.
+ """
+ current = path.read_text()
+ out = replace_snippet(current, snippet, start_marker, end_marker)
+
+ if not dry_run:
+ _writelines(path, out)
+ return
+
+ relative = path.relative_to(
+ pathlib.Path(__file__).resolve().parent.parent.parent.parent
+ )
+ name = f"{relative}"
+ diff = unified_diff(name, current, out)
+ if diff:
+ print(f"Diff of the changes that would be made to '{name}':\n{diff}")
+ else:
+ print(f"'{name}' is up to date")
diff --git a/tools/private/update_deps/update_file_test.py b/tools/private/update_deps/update_file_test.py
new file mode 100644
index 0000000..01c6ec7
--- /dev/null
+++ b/tools/private/update_deps/update_file_test.py
@@ -0,0 +1,128 @@
+# 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 tools.private.update_deps.update_file import replace_snippet, unified_diff
+
+
+class TestReplaceSnippet(unittest.TestCase):
+ def test_replace_simple(self):
+ current = """\
+Before the snippet
+
+# Start marker
+To be replaced
+It may have the '# Start marker' or '# End marker' in the middle,
+But it has to be in the beginning of the line to mark the end of a region.
+# End marker
+
+After the snippet
+"""
+ snippet = "Replaced"
+ got = replace_snippet(
+ current=current,
+ snippet="Replaced",
+ start_marker="# Start marker",
+ end_marker="# End marker",
+ )
+
+ want = """\
+Before the snippet
+
+# Start marker
+Replaced
+# End marker
+
+After the snippet
+"""
+ self.assertEqual(want, got)
+
+ def test_replace_indented(self):
+ current = """\
+Before the snippet
+
+ # Start marker
+ To be replaced
+ # End marker
+
+After the snippet
+"""
+ got = replace_snippet(
+ current=current,
+ snippet=" Replaced",
+ start_marker="# Start marker",
+ end_marker="# End marker",
+ )
+
+ want = """\
+Before the snippet
+
+ # Start marker
+ Replaced
+ # End marker
+
+After the snippet
+"""
+ self.assertEqual(want, got)
+
+ def test_raises_if_start_is_not_found(self):
+ with self.assertRaises(RuntimeError) as exc:
+ replace_snippet(
+ current="foo",
+ snippet="",
+ start_marker="start",
+ end_marker="end",
+ )
+
+ self.assertEqual(exc.exception.args[0], "Start marker 'start' was not found")
+
+ def test_raises_if_end_is_not_found(self):
+ with self.assertRaises(RuntimeError) as exc:
+ replace_snippet(
+ current="start",
+ snippet="",
+ start_marker="start",
+ end_marker="end",
+ )
+
+ self.assertEqual(exc.exception.args[0], "End marker 'end' was not found")
+
+
+class TestUnifiedDiff(unittest.TestCase):
+ def test_diff(self):
+ give_a = """\
+First line
+second line
+Third line
+"""
+ give_b = """\
+First line
+Second line
+Third line
+"""
+ got = unified_diff("filename", give_a, give_b)
+ want = """\
+--- a/filename
++++ b/filename
+@@ -1,3 +1,3 @@
+ First line
+-second line
++Second line
+ Third line"""
+ self.assertEqual(want, got)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tools/private/update_deps/update_pip_deps.py b/tools/private/update_deps/update_pip_deps.py
new file mode 100755
index 0000000..8a2dd5f
--- /dev/null
+++ b/tools/private/update_deps/update_pip_deps.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+# 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.
+
+"""A script to manage internal pip dependencies."""
+
+from __future__ import annotations
+
+import argparse
+import json
+import os
+import pathlib
+import re
+import sys
+import tempfile
+import textwrap
+from dataclasses import dataclass
+
+from pip._internal.cli.main import main as pip_main
+
+from tools.private.update_deps.args import path_from_runfiles
+from tools.private.update_deps.update_file import update_file
+
+
+@dataclass
+class Dep:
+ name: str
+ url: str
+ sha256: str
+
+
+def _dep_snippet(deps: list[Dep]) -> str:
+ lines = []
+ for dep in deps:
+ lines.extend(
+ [
+ "(\n",
+ f' "{dep.name}",\n',
+ f' "{dep.url}",\n',
+ f' "{dep.sha256}",\n',
+ "),\n",
+ ]
+ )
+
+ return textwrap.indent("".join(lines), " " * 4)
+
+
+def _module_snippet(deps: list[Dep]) -> str:
+ lines = []
+ for dep in deps:
+ lines.append(f'"{dep.name}",\n')
+
+ return textwrap.indent("".join(lines), " " * 4)
+
+
+def _generate_report(requirements_txt: pathlib.Path) -> dict:
+ with tempfile.NamedTemporaryFile() as tmp:
+ tmp_path = pathlib.Path(tmp.name)
+ sys.argv = [
+ "pip",
+ "install",
+ "--dry-run",
+ "--ignore-installed",
+ "--report",
+ f"{tmp_path}",
+ "-r",
+ f"{requirements_txt}",
+ ]
+ pip_main()
+ with open(tmp_path) as f:
+ return json.load(f)
+
+
+def _get_deps(report: dict) -> list[Dep]:
+ deps = []
+ for dep in report["install"]:
+ try:
+ dep = Dep(
+ name="pypi__"
+ + re.sub(
+ "[._-]+",
+ "_",
+ dep["metadata"]["name"],
+ ),
+ url=dep["download_info"]["url"],
+ sha256=dep["download_info"]["archive_info"]["hash"][len("sha256=") :],
+ )
+ except:
+ debug_dep = textwrap.indent(json.dumps(dep, indent=4), " " * 4)
+ print(f"Could not parse the response from 'pip':\n{debug_dep}")
+ raise
+
+ deps.append(dep)
+
+ return sorted(deps, key=lambda dep: dep.name)
+
+
+def main():
+ parser = argparse.ArgumentParser(__doc__)
+ parser.add_argument(
+ "--start",
+ type=str,
+ default="# START: maintained by 'bazel run //tools/private:update_pip_deps'",
+ help="The text to match in a file when updating them.",
+ )
+ parser.add_argument(
+ "--end",
+ type=str,
+ default="# END: maintained by 'bazel run //tools/private:update_pip_deps'",
+ help="The text to match in a file when updating them.",
+ )
+ parser.add_argument(
+ "--dry-run",
+ action="store_true",
+ help="Wether to write to files",
+ )
+ parser.add_argument(
+ "--requirements-txt",
+ type=path_from_runfiles,
+ default=os.environ.get("REQUIREMENTS_TXT"),
+ help="The requirements.txt path for the pip_install tools, defaults to the value taken from REQUIREMENTS_TXT",
+ )
+ parser.add_argument(
+ "--module-bazel",
+ type=path_from_runfiles,
+ default=os.environ.get("MODULE_BAZEL"),
+ help="The path for the file to be updated, defaults to the value taken from MODULE_BAZEL",
+ )
+ parser.add_argument(
+ "--repositories-bzl",
+ type=path_from_runfiles,
+ default=os.environ.get("REPOSITORIES_BZL"),
+ help="The path for the file to be updated, defaults to the value taken from REPOSITORIES_BZL",
+ )
+ args = parser.parse_args()
+
+ report = _generate_report(args.requirements_txt)
+ deps = _get_deps(report)
+
+ update_file(
+ path=args.repositories_bzl,
+ snippet=_dep_snippet(deps),
+ start_marker=args.start,
+ end_marker=args.end,
+ dry_run=args.dry_run,
+ )
+
+ update_file(
+ path=args.module_bazel,
+ snippet=_module_snippet(deps),
+ start_marker=args.start,
+ end_marker=args.end,
+ dry_run=args.dry_run,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/publish/BUILD.bazel b/tools/publish/BUILD.bazel
index 065e56b..4759a31 100644
--- a/tools/publish/BUILD.bazel
+++ b/tools/publish/BUILD.bazel
@@ -2,6 +2,7 @@ load("//python:pip.bzl", "compile_pip_requirements")
compile_pip_requirements(
name = "requirements",
+ src = "requirements.in",
requirements_darwin = "requirements_darwin.txt",
requirements_windows = "requirements_windows.txt",
)
diff --git a/tools/publish/requirements_darwin.txt b/tools/publish/requirements_darwin.txt
index cb35e69..1203ba2 100644
--- a/tools/publish/requirements_darwin.txt
+++ b/tools/publish/requirements_darwin.txt
@@ -176,9 +176,9 @@ twine==4.0.2 \
--hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \
--hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8
# via -r tools/publish/requirements.in
-urllib3==1.26.14 \
- --hash=sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72 \
- --hash=sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via
# requests
# twine
diff --git a/tools/publish/requirements_windows.txt b/tools/publish/requirements_windows.txt
index cd175c6..25d7776 100644
--- a/tools/publish/requirements_windows.txt
+++ b/tools/publish/requirements_windows.txt
@@ -180,9 +180,9 @@ twine==4.0.2 \
--hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \
--hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8
# via -r tools/publish/requirements.in
-urllib3==1.26.14 \
- --hash=sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72 \
- --hash=sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1
+urllib3==1.26.18 \
+ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
+ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
# via
# requests
# twine
diff --git a/tools/bazel_integration_test/update_deleted_packages.sh b/tools/update_deleted_packages.sh
index 54db026..17e33d1 100755
--- a/tools/bazel_integration_test/update_deleted_packages.sh
+++ b/tools/update_deleted_packages.sh
@@ -25,7 +25,7 @@
set -euxo pipefail
-DIR="$(dirname $0)/../.."
+DIR="$(dirname $0)/.."
cd $DIR
# The sed -i.bak pattern is compatible between macos and linux
diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py
index 63b833f..3bfaba2 100644
--- a/tools/wheelmaker.py
+++ b/tools/wheelmaker.py
@@ -12,9 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+
import argparse
import base64
-import collections
import hashlib
import os
import re
@@ -22,6 +23,8 @@ import sys
import zipfile
from pathlib import Path
+_ZIP_EPOCH = (1980, 1, 1, 0, 0, 0)
+
def commonpath(path1, path2):
ret = []
@@ -33,10 +36,177 @@ def commonpath(path1, path2):
def escape_filename_segment(segment):
- """Escapes a filename segment per https://www.python.org/dev/peps/pep-0427/#escaping-and-unicode"""
+ """Escapes a filename segment per https://www.python.org/dev/peps/pep-0427/#escaping-and-unicode
+
+ This is a legacy function, kept for backwards compatibility,
+ and may be removed in the future. See `escape_filename_distribution_name`
+ and `normalize_pep440` for the modern alternatives.
+ """
return re.sub(r"[^\w\d.]+", "_", segment, re.UNICODE)
+def normalize_package_name(name):
+ """Normalize a package name according to the Python Packaging User Guide.
+
+ See https://packaging.python.org/en/latest/specifications/name-normalization/
+ """
+ return re.sub(r"[-_.]+", "-", name).lower()
+
+
+def escape_filename_distribution_name(name):
+ """Escape the distribution name component of a filename.
+
+ See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
+ """
+ return normalize_package_name(name).replace("-", "_")
+
+
+def normalize_pep440(version):
+ """Normalize version according to PEP 440, with fallback for placeholders.
+
+ If there's a placeholder in braces, such as {BUILD_TIMESTAMP},
+ replace it with 0. Such placeholders can be used with stamping, in
+ which case they would have been resolved already by now; if they
+ haven't, we're doing an unstamped build, but we still need to
+ produce a valid version. If such replacements are made, the
+ original version string, sanitized to dot-separated alphanumerics,
+ is appended as a local version segment, so you understand what
+ placeholder was involved.
+
+ If that still doesn't produce a valid version, use version 0 and
+ append the original version string, sanitized to dot-separated
+ alphanumerics, as a local version segment.
+
+ """
+
+ import packaging.version
+
+ try:
+ return str(packaging.version.Version(version))
+ except packaging.version.InvalidVersion:
+ pass
+
+ sanitized = re.sub(r"[^a-z0-9]+", ".", version.lower()).strip(".")
+ substituted = re.sub(r"\{\w+\}", "0", version)
+ delimiter = "." if "+" in substituted else "+"
+ try:
+ return str(packaging.version.Version(f"{substituted}{delimiter}{sanitized}"))
+ except packaging.version.InvalidVersion:
+ return str(packaging.version.Version(f"0+{sanitized}"))
+
+
+class _WhlFile(zipfile.ZipFile):
+ def __init__(
+ self,
+ filename,
+ *,
+ mode,
+ distinfo_dir: str | Path,
+ strip_path_prefixes=None,
+ compression=zipfile.ZIP_DEFLATED,
+ **kwargs,
+ ):
+ self._distinfo_dir: str = Path(distinfo_dir).name
+ self._strip_path_prefixes = strip_path_prefixes or []
+ # Entries for the RECORD file as (filename, hash, size) tuples.
+ self._record = []
+
+ super().__init__(filename, mode=mode, compression=compression, **kwargs)
+
+ def distinfo_path(self, basename):
+ return f"{self._distinfo_dir}/{basename}"
+
+ def add_file(self, package_filename, real_filename):
+ """Add given file to the distribution."""
+
+ def arcname_from(name):
+ # Always use unix path separators.
+ normalized_arcname = name.replace(os.path.sep, "/")
+ # Don't manipulate names filenames in the .distinfo directory.
+ if normalized_arcname.startswith(self._distinfo_dir):
+ return normalized_arcname
+ for prefix in self._strip_path_prefixes:
+ if normalized_arcname.startswith(prefix):
+ return normalized_arcname[len(prefix) :]
+
+ return normalized_arcname
+
+ if os.path.isdir(real_filename):
+ directory_contents = os.listdir(real_filename)
+ for file_ in directory_contents:
+ self.add_file(
+ "{}/{}".format(package_filename, file_),
+ "{}/{}".format(real_filename, file_),
+ )
+ return
+
+ arcname = arcname_from(package_filename)
+ zinfo = self._zipinfo(arcname)
+
+ # Write file to the zip archive while computing the hash and length
+ hash = hashlib.sha256()
+ size = 0
+ with open(real_filename, "rb") as fsrc:
+ with self.open(zinfo, "w") as fdst:
+ while True:
+ block = fsrc.read(2**20)
+ if not block:
+ break
+ fdst.write(block)
+ hash.update(block)
+ size += len(block)
+
+ self._add_to_record(arcname, self._serialize_digest(hash), size)
+
+ def add_string(self, filename, contents):
+ """Add given 'contents' as filename to the distribution."""
+ if isinstance(contents, str):
+ contents = contents.encode("utf-8", "surrogateescape")
+ zinfo = self._zipinfo(filename)
+ self.writestr(zinfo, contents)
+ hash = hashlib.sha256()
+ hash.update(contents)
+ self._add_to_record(filename, self._serialize_digest(hash), len(contents))
+
+ def _serialize_digest(self, hash):
+ # https://www.python.org/dev/peps/pep-0376/#record
+ # "base64.urlsafe_b64encode(digest) with trailing = removed"
+ digest = base64.urlsafe_b64encode(hash.digest())
+ digest = b"sha256=" + digest.rstrip(b"=")
+ return digest
+
+ def _add_to_record(self, filename, hash, size):
+ size = str(size).encode("ascii")
+ self._record.append((filename, hash, size))
+
+ def _zipinfo(self, filename):
+ """Construct deterministic ZipInfo entry for a file named filename"""
+ # Strip leading path separators to mirror ZipInfo.from_file behavior
+ separators = os.path.sep
+ if os.path.altsep is not None:
+ separators += os.path.altsep
+ arcname = filename.lstrip(separators)
+
+ zinfo = zipfile.ZipInfo(filename=arcname, date_time=_ZIP_EPOCH)
+ zinfo.create_system = 3 # ZipInfo entry created on a unix-y system
+ zinfo.external_attr = 0o777 << 16 # permissions: rwxrwxrwx
+ zinfo.compress_type = self.compression
+ return zinfo
+
+ def add_recordfile(self):
+ """Write RECORD file to the distribution."""
+ record_path = self.distinfo_path("RECORD")
+ entries = self._record + [(record_path, b"", b"")]
+ contents = b""
+ for filename, digest, size in entries:
+ if isinstance(filename, str):
+ filename = filename.lstrip("/").encode("utf-8", "surrogateescape")
+ contents += b"%s,%s,%s\n" % (filename, digest, size)
+
+ self.add_string(record_path, contents)
+ return contents
+
+
class WheelMaker(object):
def __init__(
self,
@@ -48,6 +218,8 @@ class WheelMaker(object):
platform,
outfile=None,
strip_path_prefixes=None,
+ incompatible_normalize_name=True,
+ incompatible_normalize_version=True,
):
self._name = name
self._version = version
@@ -56,32 +228,52 @@ class WheelMaker(object):
self._abi = abi
self._platform = platform
self._outfile = outfile
- self._strip_path_prefixes = (
- strip_path_prefixes if strip_path_prefixes is not None else []
- )
+ self._strip_path_prefixes = strip_path_prefixes
- self._distinfo_dir = (
- escape_filename_segment(self._name)
- + "-"
- + escape_filename_segment(self._version)
- + ".dist-info/"
- )
- self._zipfile = None
- # Entries for the RECORD file as (filename, hash, size) tuples.
- self._record = []
+ if incompatible_normalize_version:
+ self._version = normalize_pep440(self._version)
+ self._escaped_version = self._version
+ else:
+ self._escaped_version = escape_filename_segment(self._version)
+
+ if incompatible_normalize_name:
+ escaped_name = escape_filename_distribution_name(self._name)
+ self._distinfo_dir = (
+ escaped_name + "-" + self._escaped_version + ".dist-info/"
+ )
+ self._wheelname_fragment_distribution_name = escaped_name
+ else:
+ # The legacy behavior escapes the distinfo dir but not the
+ # wheel name. Enable incompatible_normalize_name to fix it.
+ # https://github.com/bazelbuild/rules_python/issues/1132
+ self._distinfo_dir = (
+ escape_filename_segment(self._name)
+ + "-"
+ + self._escaped_version
+ + ".dist-info/"
+ )
+ self._wheelname_fragment_distribution_name = self._name
+
+ self._whlfile = None
def __enter__(self):
- self._zipfile = zipfile.ZipFile(
- self.filename(), mode="w", compression=zipfile.ZIP_DEFLATED
+ self._whlfile = _WhlFile(
+ self.filename(),
+ mode="w",
+ distinfo_dir=self._distinfo_dir,
+ strip_path_prefixes=self._strip_path_prefixes,
)
return self
def __exit__(self, type, value, traceback):
- self._zipfile.close()
- self._zipfile = None
+ self._whlfile.close()
+ self._whlfile = None
def wheelname(self) -> str:
- components = [self._name, self._version]
+ components = [
+ self._wheelname_fragment_distribution_name,
+ self._version,
+ ]
if self._build_tag:
components.append(self._build_tag)
components += [self._python_tag, self._abi, self._platform]
@@ -96,62 +288,11 @@ class WheelMaker(object):
return ["-".join([self._python_tag, self._abi, self._platform])]
def distinfo_path(self, basename):
- return self._distinfo_dir + basename
-
- def _serialize_digest(self, hash):
- # https://www.python.org/dev/peps/pep-0376/#record
- # "base64.urlsafe_b64encode(digest) with trailing = removed"
- digest = base64.urlsafe_b64encode(hash.digest())
- digest = b"sha256=" + digest.rstrip(b"=")
- return digest
-
- def add_string(self, filename, contents):
- """Add given 'contents' as filename to the distribution."""
- if sys.version_info[0] > 2 and isinstance(contents, str):
- contents = contents.encode("utf-8", "surrogateescape")
- self._zipfile.writestr(filename, contents)
- hash = hashlib.sha256()
- hash.update(contents)
- self._add_to_record(filename, self._serialize_digest(hash), len(contents))
+ return self._whlfile.distinfo_path(basename)
def add_file(self, package_filename, real_filename):
"""Add given file to the distribution."""
-
- def arcname_from(name):
- # Always use unix path separators.
- normalized_arcname = name.replace(os.path.sep, "/")
- # Don't manipulate names filenames in the .distinfo directory.
- if normalized_arcname.startswith(self._distinfo_dir):
- return normalized_arcname
- for prefix in self._strip_path_prefixes:
- if normalized_arcname.startswith(prefix):
- return normalized_arcname[len(prefix) :]
-
- return normalized_arcname
-
- if os.path.isdir(real_filename):
- directory_contents = os.listdir(real_filename)
- for file_ in directory_contents:
- self.add_file(
- "{}/{}".format(package_filename, file_),
- "{}/{}".format(real_filename, file_),
- )
- return
-
- arcname = arcname_from(package_filename)
-
- self._zipfile.write(real_filename, arcname=arcname)
- # Find the hash and length
- hash = hashlib.sha256()
- size = 0
- with open(real_filename, "rb") as f:
- while True:
- block = f.read(2**20)
- if not block:
- break
- hash.update(block)
- size += len(block)
- self._add_to_record(arcname, self._serialize_digest(hash), size)
+ self._whlfile.add_file(package_filename, real_filename)
def add_wheelfile(self):
"""Write WHEEL file to the distribution"""
@@ -165,7 +306,7 @@ Root-Is-Purelib: {}
)
for tag in self.disttags():
wheel_contents += "Tag: %s\n" % tag
- self.add_string(self.distinfo_path("WHEEL"), wheel_contents)
+ self._whlfile.add_string(self.distinfo_path("WHEEL"), wheel_contents)
def add_metadata(self, metadata, name, description, version):
"""Write METADATA file to the distribution."""
@@ -177,23 +318,11 @@ Root-Is-Purelib: {}
# provided.
metadata += description if description else "UNKNOWN"
metadata += "\n"
- self.add_string(self.distinfo_path("METADATA"), metadata)
+ self._whlfile.add_string(self.distinfo_path("METADATA"), metadata)
def add_recordfile(self):
"""Write RECORD file to the distribution."""
- record_path = self.distinfo_path("RECORD")
- entries = self._record + [(record_path, b"", b"")]
- entries.sort()
- contents = b""
- for filename, digest, size in entries:
- if sys.version_info[0] > 2 and isinstance(filename, str):
- filename = filename.lstrip("/").encode("utf-8", "surrogateescape")
- contents += b"%s,%s,%s\n" % (filename, digest, size)
- self.add_string(record_path, contents)
-
- def _add_to_record(self, filename, hash, size):
- size = str(size).encode("ascii")
- self._record.append((filename, hash, size))
+ self._whlfile.add_recordfile()
def get_files_to_package(input_files):
@@ -330,6 +459,12 @@ def parse_args() -> argparse.Namespace:
help="Pass in the stamp info file for stamping",
)
+ feature_group = parser.add_argument_group("Feature flags")
+ feature_group.add_argument("--noincompatible_normalize_name", action="store_true")
+ feature_group.add_argument(
+ "--noincompatible_normalize_version", action="store_true"
+ )
+
return parser.parse_args(sys.argv[1:])
@@ -386,6 +521,8 @@ def main() -> None:
platform=arguments.platform,
outfile=arguments.out,
strip_path_prefixes=strip_prefixes,
+ incompatible_normalize_name=not arguments.noincompatible_normalize_name,
+ incompatible_normalize_version=not arguments.noincompatible_normalize_version,
) as maker:
for package_filename, real_filename in all_files:
maker.add_file(package_filename, real_filename)
@@ -393,25 +530,24 @@ def main() -> None:
description = None
if arguments.description_file:
- if sys.version_info[0] == 2:
- with open(arguments.description_file, "rt") as description_file:
- description = description_file.read()
- else:
- with open(
- arguments.description_file, "rt", encoding="utf-8"
- ) as description_file:
- description = description_file.read()
+ with open(
+ arguments.description_file, "rt", encoding="utf-8"
+ ) as description_file:
+ description = description_file.read()
metadata = None
- if sys.version_info[0] == 2:
- with open(arguments.metadata_file, "rt") as metadata_file:
- metadata = metadata_file.read()
- else:
- with open(arguments.metadata_file, "rt", encoding="utf-8") as metadata_file:
- metadata = metadata_file.read()
+ with open(arguments.metadata_file, "rt", encoding="utf-8") as metadata_file:
+ metadata = metadata_file.read()
+ if arguments.noincompatible_normalize_version:
+ version_in_metadata = version
+ else:
+ version_in_metadata = normalize_pep440(version)
maker.add_metadata(
- metadata=metadata, name=name, description=description, version=version
+ metadata=metadata,
+ name=name,
+ description=description,
+ version=version_in_metadata,
)
if arguments.entry_points_file:
diff --git a/version.bzl b/version.bzl
index 8c7f01c..2e8fc0b 100644
--- a/version.bzl
+++ b/version.bzl
@@ -17,22 +17,22 @@
# against.
# This version should be updated together with the version of Bazel
# in .bazelversion.
-BAZEL_VERSION = "6.0.0"
+BAZEL_VERSION = "7.0.0"
# NOTE: Keep in sync with .bazelci/presubmit.yml
# This is the minimum supported bazel version, that we have some tests for.
-MINIMUM_BAZEL_VERSION = "5.4.0"
+MINIMUM_BAZEL_VERSION = "6.4.0"
# Versions of Bazel which users should be able to use.
# Ensures we don't break backwards-compatibility,
# accidentally forcing users to update their LTS-supported bazel.
# These are the versions used when testing nested workspaces with
-# bazel_integration_test.
+# rules_bazel_integration_test.
+#
+# Keep in sync with MODULE.bazel's bazel_binaries config
SUPPORTED_BAZEL_VERSIONS = [
BAZEL_VERSION,
- # TODO @aignas 2023-02-15: the integration tests currently support
- # only a single element in this array.
- #MINIMUM_BAZEL_VERSION,
+ MINIMUM_BAZEL_VERSION,
]
def bazel_version_to_binary_label(version):