From b4e64960eca92b3d66b8147f964e69cbd40004a4 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Wed, 22 Apr 2026 18:39:54 -0700 Subject: [PATCH 01/40] basic impl ref https://packaging.python.org/en/latest/specifications/binary-distribution-format/#installing-a-wheel-distribution-1-0-py32-none-any-whl for generic data scheme: these are usually installed to the venv root, but that seems ill-advised. So we install into a data sub-directory of the venv. --- MODULE.bazel | 1 + python/config_settings/BUILD.bazel | 2 +- python/private/internal_dev_deps.bzl | 11 +++++++ python/private/py_executable.bzl | 23 +++++++++----- python/private/py_info.bzl | 1 + python/private/pypi/whl_library_targets.bzl | 14 +++++++-- python/private/venv_runfiles.bzl | 31 ++++++++++++++++--- .../whl_library_targets_tests.bzl | 12 +++---- tests/repos/whl_with_data/BUILD.bazel | 1 + .../data/whl_with_data/data_data_file.txt | 1 + .../headers/whl_with_data/header_file.h | 1 + .../platlib/whl_with_data/platlib_file.txt | 1 + .../purelib/whl_with_data/__init__.py | 0 .../purelib/whl_with_data/data_file.txt | 1 + .../scripts/whl_script.sh | 1 + .../whl_with_data-1.0.dist-info/METADATA | 3 ++ .../whl_with_data-1.0.dist-info/RECORD | 6 ++++ .../whl_with_data-1.0.dist-info/WHEEL | 1 + tests/venv_site_packages_libs/BUILD.bazel | 1 + tests/venv_site_packages_libs/bin.py | 29 ++++++++++++++++- 20 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 tests/repos/whl_with_data/BUILD.bazel create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.data/headers/whl_with_data/header_file.h create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/__init__.py create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.data/scripts/whl_script.sh create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD create mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.dist-info/WHEEL diff --git a/MODULE.bazel b/MODULE.bazel index 95d6b9e3a9..ff5c369b8b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -246,6 +246,7 @@ use_repo( "somepkg_with_build_files", "whl_library_extras_direct_dep", "whl_with_build_files", + "whl_with_data", ) dev_rules_python_config = use_extension( diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 7060d50b26..fc0ac51451 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -229,7 +229,7 @@ string_flag( ) config_setting( - name = "is_venvs_site_packages", + name = "_is_venvs_site_packages_yes", flag_values = { ":venvs_site_packages": VenvsSitePackages.YES, }, diff --git a/python/private/internal_dev_deps.bzl b/python/private/internal_dev_deps.bzl index fbdd5711b1..b615ca0099 100644 --- a/python/private/internal_dev_deps.bzl +++ b/python/private/internal_dev_deps.bzl @@ -91,6 +91,17 @@ def _internal_dev_deps_impl(mctx): enable_implicit_namespace_pkgs = False, ) + whl_from_dir_repo( + name = "whl_with_data_whl", + root = "//tests/repos/whl_with_data:BUILD.bazel", + output = "whl_with_data-1.0-any-none-any.whl", + ) + whl_library( + name = "whl_with_data", + whl_file = "@whl_with_data_whl//:whl_with_data-1.0-any-none-any.whl", + requirement = "whl-with-data", + ) + _whl_library_from_dir( name = "whl_library_extras_direct_dep", root = "//tests/pypi/whl_library/testdata/pkg:BUILD.bazel", diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 375030ce91..ab09926faa 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -576,8 +576,10 @@ def _create_venv(ctx, output_prefix, imports, runtime_details, add_runfiles_root ) venv_dir_map = { - VenvSymlinkKind.BIN: venv_details.bin_dir, + VenvSymlinkKind.BIN: "{}/{}".format(venv_ctx_rel_root, venv_details.bin_dir), VenvSymlinkKind.LIB: site_packages, + VenvSymlinkKind.INCLUDE: "{}/{}".format(venv_ctx_rel_root, venv_details.include_dir), + VenvSymlinkKind.DATA: "{}/data".format(venv_ctx_rel_root), } venv_app_files = create_venv_app_files( ctx, @@ -659,7 +661,7 @@ def _create_venv_unixy(ctx, *, venv_ctx_rel_root, runtime, interpreter_actual_pa recreate_venv_at_runtime = False - bin_dir = "{}/bin".format(venv_ctx_rel_root) + venv_bin_ctx_rel_path = "{}/bin".format(venv_ctx_rel_root) if create_full_venv: # Some wrappers around the interpreter (e.g. pyenv) use the program # name to decide what to do, so preserve the name. @@ -671,7 +673,7 @@ def _create_venv_unixy(ctx, *, venv_ctx_rel_root, runtime, interpreter_actual_pa # When the venv symlinks are disabled, the $venv/bin/python3 file isn't # needed or used at runtime. However, the zip code uses the interpreter # File object to figure out some paths. - interpreter = ctx.actions.declare_file("{}/{}".format(bin_dir, py_exe_basename)) + interpreter = ctx.actions.declare_file("{}/{}".format(venv_bin_ctx_rel_path, py_exe_basename)) ctx.actions.write(interpreter, "actual:{}".format(interpreter_actual_path)) elif runtime.interpreter: @@ -679,7 +681,7 @@ def _create_venv_unixy(ctx, *, venv_ctx_rel_root, runtime, interpreter_actual_pa # declare_symlink() is required to ensure that the resulting file # in runfiles is always a symlink. An RBE implementation, for example, # may choose to write what symlink() points to instead. - interpreter = ctx.actions.declare_symlink("{}/{}".format(bin_dir, py_exe_basename)) + interpreter = ctx.actions.declare_symlink("{}/{}".format(venv_bin_ctx_rel_path, py_exe_basename)) interpreter_runfiles.add(interpreter) rel_path = relative_path( @@ -690,7 +692,7 @@ def _create_venv_unixy(ctx, *, venv_ctx_rel_root, runtime, interpreter_actual_pa ) ctx.actions.symlink(output = interpreter, target_path = rel_path) else: - interpreter = ctx.actions.declare_symlink("{}/{}".format(bin_dir, py_exe_basename)) + interpreter = ctx.actions.declare_symlink("{}/{}".format(venv_bin_ctx_rel_path, py_exe_basename)) interpreter_runfiles.add(interpreter) ctx.actions.symlink(output = interpreter, target_path = runtime.interpreter_path) else: @@ -715,7 +717,8 @@ def _create_venv_unixy(ctx, *, venv_ctx_rel_root, runtime, interpreter_actual_pa interpreter = interpreter, pyvenv_cfg = pyvenv_cfg, site_packages = site_packages, - bin_dir = bin_dir, + bin_dir = "bin", + include_dir = "include", recreate_venv_at_runtime = recreate_venv_at_runtime, interpreter_runfiles = interpreter_runfiles.build(ctx), interpreter_symlinks = depset(), @@ -777,7 +780,8 @@ def _create_venv_windows(ctx, *, venv_ctx_rel_root, runtime, interpreter_actual_ interpreter = interpreter, pyvenv_cfg = None, site_packages = site_packages, - bin_dir = venv_bin_ctx_rel_path, + bin_dir = venv_bin_rel_path, + include_dir = "Include", recreate_venv_at_runtime = True, interpreter_runfiles = interpreter_runfiles.build(ctx), interpreter_symlinks = interpreter_symlinks.build(), @@ -789,6 +793,7 @@ def _venv_details( pyvenv_cfg, site_packages, bin_dir, + include_dir, recreate_venv_at_runtime, interpreter_runfiles, interpreter_symlinks): @@ -801,8 +806,10 @@ def _venv_details( pyvenv_cfg = pyvenv_cfg, # str; venv-relative path to the site-packages directory site_packages = site_packages, - # str; ctx-relative path to the venv's bin directory. + # str; venv-relative path to the venv's bin directory. bin_dir = bin_dir, + # str; venv-relative-path to the venv's include directory. + include_dir = include_dir, # bool; True if the venv needs to be recreated at runtime (because the # build-time construction isn't sufficient). False if the build-time # constructed venv is sufficient. diff --git a/python/private/py_info.bzl b/python/private/py_info.bzl index 8868b9d3b4..28056f906c 100644 --- a/python/private/py_info.bzl +++ b/python/private/py_info.bzl @@ -45,6 +45,7 @@ VenvSymlinkKind = struct( BIN = "BIN", LIB = "LIB", INCLUDE = "INCLUDE", + DATA = "DATA", ) def _VenvSymlinkEntry_init(**kwargs): diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index dc99aab532..8c317f4886 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -43,6 +43,8 @@ _BAZEL_REPO_FILE_GLOBS = [ "WORKSPACE.bazel", ] +_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:_is_venvs_site_packages_yes") + def whl_library_targets_from_requires( *, name, @@ -194,8 +196,10 @@ def whl_library_targets( DIST_INFO_LABEL: dict( include = ["site-packages/*.dist-info/**"], ), + + ## TO CHECK: should bin/ and include/ be part of the data target? DATA_LABEL: dict( - include = ["data/**"], + include = ["data/**", "bin/**", "include/**"], ), } @@ -356,11 +360,15 @@ def whl_library_targets( if item not in _data_exclude: _data_exclude.append(item) - data = data + native.glob( + data = data + [":" + DATA_LABEL] + native.glob( ["site-packages/**/*"], exclude = _data_exclude, allow_empty = True, ) + data = data + select({ + _IS_VENV_SITE_PACKAGES_YES: [DATA_LABEL], + "//conditions:default": [], + }) pyi_srcs = native.glob( ["site-packages/**/*.pyi"], @@ -369,7 +377,7 @@ def whl_library_targets( if not enable_implicit_namespace_pkgs: generated_namespace_package_files = select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + _IS_VENV_SITE_PACKAGES_YES: [], "//conditions:default": rules.create_inits( srcs = srcs + data + pyi_srcs, ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so. diff --git a/python/private/venv_runfiles.bzl b/python/private/venv_runfiles.bzl index 6daf0d4e5c..d70fecb387 100644 --- a/python/private/venv_runfiles.bzl +++ b/python/private/venv_runfiles.bzl @@ -275,10 +275,16 @@ def _get_file_venv_path(ctx, f, site_packages_root): Returns: A tuple `(venv_path, rf_root_path)` if the file is under - `site_packages_root`, otherwise `(None, None)`. + `site_packages_root` or data/, bin/, include/ otherwise `(None, None)`. """ rf_root_path = runfiles_root_path(ctx, f.short_path) _, _, repo_rel_path = rf_root_path.partition("/") + + # Check for wheel data/bin/include folders first + for prefix in ["data/", "bin/", "include/"]: + if repo_rel_path.startswith(prefix): + return (repo_rel_path, rf_root_path) + head, found_sp_root, venv_path = repo_rel_path.partition(site_packages_root) if head or not found_sp_root: # If head is set, then the path didn't start with site_packages_root @@ -452,19 +458,36 @@ def get_venv_symlinks( # Finally, for each group, we create the VenvSymlinkEntry objects for venv_path, files in optimized_groups.items(): + if venv_path.startswith("data/"): + out_venv_path = venv_path[len("data/"):] + kind = VenvSymlinkKind.DATA + prefix = "" + elif venv_path.startswith("include/"): + out_venv_path = venv_path[len("include/"):] + kind = VenvSymlinkKind.INCLUDE + prefix = "" + elif venv_path.startswith("bin/"): + out_venv_path = venv_path[len("bin/"):] + kind = VenvSymlinkKind.BIN + prefix = "" + else: + out_venv_path = venv_path + kind = VenvSymlinkKind.LIB + prefix = site_packages_root + link_to_path = ( _get_label_runfiles_repo(ctx, files[0].owner) + "/" + - site_packages_root + + prefix + venv_path ) venv_symlinks[venv_path] = VenvSymlinkEntry( - kind = VenvSymlinkKind.LIB, + kind = kind, link_to_path = link_to_path, link_to_file = None, package = package, version = version_str, - venv_path = venv_path, + venv_path = out_venv_path, files = depset(files), ) diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl index 08715fbf77..ae6e9c5a08 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -245,7 +245,7 @@ def _test_whl_and_library_deps_from_requires(env): env.expect.that_dict(py_library_call).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], @@ -259,7 +259,7 @@ def _test_whl_and_library_deps_from_requires(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -361,7 +361,7 @@ def _test_whl_and_library_deps(env): env.expect.that_dict(py_library_calls[0]).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], @@ -386,7 +386,7 @@ def _test_whl_and_library_deps(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -444,7 +444,7 @@ def _test_group(env): ).contains_exactly({ "name": "_pkg", "srcs": ["site-packages/foo/srcs.py"] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/pyi.pyi"], @@ -459,7 +459,7 @@ def _test_group(env): "visibility": ["@pypi__config//_groups:__pkg__"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items diff --git a/tests/repos/whl_with_data/BUILD.bazel b/tests/repos/whl_with_data/BUILD.bazel new file mode 100644 index 0000000000..af49d1ebbf --- /dev/null +++ b/tests/repos/whl_with_data/BUILD.bazel @@ -0,0 +1 @@ +exports_files(glob(["*"])) diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt b/tests/repos/whl_with_data/whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt new file mode 100644 index 0000000000..39ec676600 --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt @@ -0,0 +1 @@ +from .data/data diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/headers/whl_with_data/header_file.h b/tests/repos/whl_with_data/whl_with_data-1.0.data/headers/whl_with_data/header_file.h new file mode 100644 index 0000000000..59c9bf78c2 --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.data/headers/whl_with_data/header_file.h @@ -0,0 +1 @@ +from .data/headers diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt b/tests/repos/whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt new file mode 100644 index 0000000000..b27295614f --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt @@ -0,0 +1 @@ +from .data/platlib diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/__init__.py b/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt b/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt new file mode 100644 index 0000000000..e547fe48ed --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt @@ -0,0 +1 @@ +from .data diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/scripts/whl_script.sh b/tests/repos/whl_with_data/whl_with_data-1.0.data/scripts/whl_script.sh new file mode 100644 index 0000000000..1a2485251c --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.data/scripts/whl_script.sh @@ -0,0 +1 @@ +#!/bin/sh diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA new file mode 100644 index 0000000000..b5ba7f8a9d --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA @@ -0,0 +1,3 @@ +Metadata-Version: 2.1 +Name: whl-with-data +Version: 1.0 diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD new file mode 100644 index 0000000000..8d655b1cec --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD @@ -0,0 +1,6 @@ +whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt,sha256=123,123 +whl_with_data-1.0.data/scripts/whl_script.sh,sha256=123,123 +whl_with_data-1.0.data/headers/whl_with_data/header_file.h,sha256=123,123 +whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt,sha256=123,123 +whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt,sha256=123,123 +whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt,sha256=123,123 diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/WHEEL b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/WHEEL new file mode 100644 index 0000000000..a64521a1cc --- /dev/null +++ b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/WHEEL @@ -0,0 +1 @@ +Wheel-Version: 1.0 diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index 56f0eb0909..5f36387083 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -45,6 +45,7 @@ py_reconfig_test( "@other//nspkg_gamma", "@other//nspkg_single", "@other//with_external_data", + "@whl_with_data//:pkg", ], ) diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 439a964906..f642781e85 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -70,7 +70,7 @@ def test_dirs_from_replaced_package_are_not_present(self): module_path = Path(module.__file__) site_packages = module_path.parent.parent - dist_info_dirs = [p.name for p in site_packages.glob("*.dist-info")] + dist_info_dirs = [p.name for p in site_packages.glob("simple*.dist-info")] self.assertEqual( ["simple-1.0.0.dist-info"], dist_info_dirs, @@ -91,6 +91,33 @@ def test_data_from_another_pkg_is_included_via_copy_file(self): files = [p.name for p in d.glob("*")] self.assertIn("another_module_data.txt", files) + def test_whl_with_data_included(self): + module = self.assert_imported_from_venv("whl_with_data") + module_path = Path(module.__file__) + site_packages = module_path.parent.parent + + # purelib + data_file = site_packages / "whl_with_data" / "data_file.txt" + self.assertTrue(data_file.exists(), f"Expected {data_file} to exist") + + # platlib + platlib_file = site_packages / "whl_with_data" / "platlib_file.txt" + self.assertTrue(platlib_file.exists(), f"Expected {platlib_file} to exist") + + venv_root = Path(self.venv) + + # data + data_data_file = venv_root / "data" / "whl_with_data" / "data_data_file.txt" + self.assertTrue(data_data_file.exists(), f"Expected {data_data_file} to exist") + + # scripts + script_file = venv_root / "bin" / "whl_script.sh" + self.assertTrue(script_file.exists(), f"Expected {script_file} to exist") + + # headers + header_file = venv_root / "include" / "whl_with_data" / "header_file.h" + self.assertTrue(header_file.exists(), f"Expected {header_file} to exist") + if __name__ == "__main__": unittest.main() From c676d6e65d20f28b6770ec39dca76e897c7935c4 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Wed, 22 Apr 2026 20:45:40 -0700 Subject: [PATCH 02/40] fix tests --- python/private/pypi/whl_library_targets.bzl | 2 +- .../whl_library_targets/whl_library_targets_tests.bzl | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 8c317f4886..400b94e3d0 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -360,7 +360,7 @@ def whl_library_targets( if item not in _data_exclude: _data_exclude.append(item) - data = data + [":" + DATA_LABEL] + native.glob( + data = data + native.glob( ["site-packages/**/*"], exclude = _data_exclude, allow_empty = True, diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl index ae6e9c5a08..659366ff05 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -50,7 +50,7 @@ def _test_filegroups(env): }, { "name": "data", - "srcs": ["data/**"], + "srcs": ["data/**", "bin/**", "include/**"], "visibility": ["//visibility:public"], }, { @@ -249,7 +249,7 @@ def _test_whl_and_library_deps_from_requires(env): "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"], + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi//bar:pkg"] + select({ ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], @@ -365,7 +365,7 @@ def _test_whl_and_library_deps(env): "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"], + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": [ "@pypi_bar_baz//:pkg", @@ -448,7 +448,7 @@ def _test_group(env): "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/pyi.pyi"], - "data": ["site-packages/foo/data.txt"], + "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi_bar_baz//:pkg"] + select({ "@platforms//os:linux": ["@pypi_box//:pkg"], From 10ace3beffc854ec7d15b144dc9a9cf62c34de6a Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 12:10:26 -0700 Subject: [PATCH 03/40] dont pass select to repo-generated init creation --- python/private/pypi/whl_library_targets.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 400b94e3d0..1745949ed7 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -360,12 +360,12 @@ def whl_library_targets( if item not in _data_exclude: _data_exclude.append(item) - data = data + native.glob( + site_packages_data = native.glob( ["site-packages/**/*"], exclude = _data_exclude, allow_empty = True, ) - data = data + select({ + data = data + site_packages_data + select({ _IS_VENV_SITE_PACKAGES_YES: [DATA_LABEL], "//conditions:default": [], }) @@ -379,7 +379,7 @@ def whl_library_targets( generated_namespace_package_files = select({ _IS_VENV_SITE_PACKAGES_YES: [], "//conditions:default": rules.create_inits( - srcs = srcs + data + pyi_srcs, + srcs = srcs + site_packages_data + pyi_srcs, ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so. root = "site-packages", ), From 0fd7c6d1e4c20124a722e030efed7d889a024889 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 12:49:38 -0700 Subject: [PATCH 04/40] fix testing on workspace --- tests/venv_site_packages_libs/BUILD.bazel | 8 ++++++-- tests/venv_site_packages_libs/bin.py | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index 5f36387083..2f4d57d6f3 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") + load("@rules_shell//shell:sh_test.bzl", "sh_test") load("//python:py_library.bzl", "py_library") load("//tests/support:py_reconfig.bzl", "py_reconfig_test") @@ -33,6 +35,9 @@ py_reconfig_test( srcs = ["bin.py"], bootstrap_impl = "script", main = "bin.py", + env = { + "BZLMOD_ENABLED": "1" if BZLMOD_ENABLED else "0", + }, venvs_site_packages = "yes", deps = [ ":closer_lib", @@ -45,8 +50,7 @@ py_reconfig_test( "@other//nspkg_gamma", "@other//nspkg_single", "@other//with_external_data", - "@whl_with_data//:pkg", - ], + ] + (["@whl_with_data//:pkg"] if BZLMOD_ENABLED else []), ) py_reconfig_test( diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index f642781e85..48cf5dadbb 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -1,4 +1,5 @@ import importlib +import os import sys import unittest from pathlib import Path @@ -91,6 +92,10 @@ def test_data_from_another_pkg_is_included_via_copy_file(self): files = [p.name for p in d.glob("*")] self.assertIn("another_module_data.txt", files) + @unittest.skipIf( + os.environ.get("BZLMOD_ENABLED") == "0", + "whl_with_data is only available with bzlmod", + ) def test_whl_with_data_included(self): module = self.assert_imported_from_venv("whl_with_data") module_path = Path(module.__file__) From 16c510038f599fd109fb1aabd182b477502b7683 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 12:54:42 -0700 Subject: [PATCH 05/40] format, lint fix --- tests/venv_site_packages_libs/BUILD.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index 2f4d57d6f3..81496f2971 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -1,4 +1,4 @@ -load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") +load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility load("@rules_shell//shell:sh_test.bzl", "sh_test") load("//python:py_library.bzl", "py_library") @@ -34,10 +34,10 @@ py_reconfig_test( name = "venvs_site_packages_libs_test", srcs = ["bin.py"], bootstrap_impl = "script", - main = "bin.py", env = { "BZLMOD_ENABLED": "1" if BZLMOD_ENABLED else "0", }, + main = "bin.py", venvs_site_packages = "yes", deps = [ ":closer_lib", From 9e53c53183460042f6e5b75fd914ed76e06bb556 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 13:01:12 -0700 Subject: [PATCH 06/40] fix pip example --- examples/pip_parse/pip_parse_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index 2fdd45477e..1ba29713d2 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -55,6 +55,7 @@ def test_data(self): self.assertListEqual( actual, [ + "bin/s3cmd", "data/share/doc/packages/s3cmd/INSTALL.md", "data/share/doc/packages/s3cmd/LICENSE", "data/share/doc/packages/s3cmd/NEWS", From 76cc0e0b051beafab52fc493b50b7e05bf9cb095 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 13:03:10 -0700 Subject: [PATCH 07/40] format --- tests/venv_site_packages_libs/BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index 81496f2971..500388d9ad 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -1,5 +1,4 @@ load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility - load("@rules_shell//shell:sh_test.bzl", "sh_test") load("//python:py_library.bzl", "py_library") load("//tests/support:py_reconfig.bzl", "py_reconfig_test") From 9470aac9b60526aaea2a389fb9a44f2dbb3f1459 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:10:42 -0700 Subject: [PATCH 08/40] test: fix windows paths for whl_with_data test Uses os.name to correctly assert the Scripts/ and Include/ directory paths when creating the virtual environment on Windows. --- tests/venv_site_packages_libs/bin.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 48cf5dadbb..cc05ccbfb1 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -111,16 +111,20 @@ def test_whl_with_data_included(self): venv_root = Path(self.venv) + is_windows = os.name == "nt" + bin_dir_name = "Scripts" if is_windows else "bin" + include_dir_name = "Include" if is_windows else "include" + # data data_data_file = venv_root / "data" / "whl_with_data" / "data_data_file.txt" self.assertTrue(data_data_file.exists(), f"Expected {data_data_file} to exist") # scripts - script_file = venv_root / "bin" / "whl_script.sh" + script_file = venv_root / bin_dir_name / "whl_script.sh" self.assertTrue(script_file.exists(), f"Expected {script_file} to exist") # headers - header_file = venv_root / "include" / "whl_with_data" / "header_file.h" + header_file = venv_root / include_dir_name / "whl_with_data" / "header_file.h" self.assertTrue(header_file.exists(), f"Expected {header_file} to exist") From 5b57de2b1cf95e6939dcf4c0fba0917e194015e9 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:23:38 -0700 Subject: [PATCH 09/40] fix: prevent grouping of top-level bin, include, and data in venvs Also add debug info to venvs_site_packages_libs_test to help diagnose Windows CI failures. --- python/private/venv_runfiles.bzl | 5 +++++ tests/venv_site_packages_libs/bin.py | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/python/private/venv_runfiles.bzl b/python/private/venv_runfiles.bzl index d70fecb387..1c518bccc3 100644 --- a/python/private/venv_runfiles.bzl +++ b/python/private/venv_runfiles.bzl @@ -418,6 +418,11 @@ def get_venv_symlinks( if not cannot_be_linked_directly.get(dirname, False): cannot_be_linked_directly[dirname] = True + # bin, include, and data are also shared across wheels, so we cannot link + # them directly if they are at the top level. + for dirname in ["bin", "include", "data"]: + cannot_be_linked_directly[dirname] = True + # At this point, venv_symlinks has entries for the shared libraries # and cannot_be_linked_directly has the directories that cannot be # directly linked. Next, we loop over the remaining files and group diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index cc05ccbfb1..24989cedcc 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -111,21 +111,30 @@ def test_whl_with_data_included(self): venv_root = Path(self.venv) - is_windows = os.name == "nt" + is_windows = sys.platform == "win32" bin_dir_name = "Scripts" if is_windows else "bin" include_dir_name = "Include" if is_windows else "include" # data data_data_file = venv_root / "data" / "whl_with_data" / "data_data_file.txt" - self.assertTrue(data_data_file.exists(), f"Expected {data_data_file} to exist") + self.assertTrue( + data_data_file.exists(), + f"Expected {data_data_file} to exist. venv_root contents: {list(venv_root.iterdir())}. os.name={os.name}, sys.platform={sys.platform}", + ) # scripts script_file = venv_root / bin_dir_name / "whl_script.sh" - self.assertTrue(script_file.exists(), f"Expected {script_file} to exist") + self.assertTrue( + script_file.exists(), + f"Expected {script_file} to exist. {bin_dir_name} contents: {list((venv_root / bin_dir_name).iterdir()) if (venv_root / bin_dir_name).exists() else 'N/A'}", + ) # headers header_file = venv_root / include_dir_name / "whl_with_data" / "header_file.h" - self.assertTrue(header_file.exists(), f"Expected {header_file} to exist") + self.assertTrue( + header_file.exists(), + f"Expected {header_file} to exist. {include_dir_name} contents: {list((venv_root / include_dir_name).iterdir()) if (venv_root / include_dir_name).exists() else 'N/A'}", + ) if __name__ == "__main__": From 103ec9a6dedada6cc4bdbf14369dad1c7e51de82 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:28:34 -0700 Subject: [PATCH 10/40] fix: add alias for is_venvs_site_packages and add whl_with_data to workspace --- internal_dev_deps.bzl | 5 +++++ python/config_settings/BUILD.bazel | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/internal_dev_deps.bzl b/internal_dev_deps.bzl index 50277ad4ad..2206197f66 100644 --- a/internal_dev_deps.bzl +++ b/internal_dev_deps.bzl @@ -65,6 +65,11 @@ def rules_python_internal_deps(): path = "tests/modules/another_module", ) + local_repository( + name = "whl_with_data", + path = "tests/repos/whl_with_data", + ) + http_archive( name = "bazel_skylib", sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index fc0ac51451..9ac6f5bde5 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -237,6 +237,13 @@ config_setting( visibility = ["//visibility:public"], ) +# TODO: Remove this once external users have migrated. +alias( + name = "is_venvs_site_packages", + actual = ":_is_venvs_site_packages_yes", + visibility = ["//visibility:public"], +) + define_pypi_internal_flags( name = "define_pypi_internal_flags", ) From f41bfdac90da9606b1a0db1099bc567d2b6e3bae Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:32:33 -0700 Subject: [PATCH 11/40] fix: add WORKSPACE file and export all files in whl_with_data repo --- tests/repos/whl_with_data/BUILD.bazel | 2 +- tests/repos/whl_with_data/WORKSPACE | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 tests/repos/whl_with_data/WORKSPACE diff --git a/tests/repos/whl_with_data/BUILD.bazel b/tests/repos/whl_with_data/BUILD.bazel index af49d1ebbf..7ef8ba4cd9 100644 --- a/tests/repos/whl_with_data/BUILD.bazel +++ b/tests/repos/whl_with_data/BUILD.bazel @@ -1 +1 @@ -exports_files(glob(["*"])) +exports_files(glob(["**"])) diff --git a/tests/repos/whl_with_data/WORKSPACE b/tests/repos/whl_with_data/WORKSPACE new file mode 100644 index 0000000000..654876d503 --- /dev/null +++ b/tests/repos/whl_with_data/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "whl_with_data") From fe1ad5f818fbca96c3f1e801a7a883029f72938c Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:39:39 -0700 Subject: [PATCH 12/40] revert: rename of is_venvs_site_packages and whl_with_data workspace addition These changes seemed to cause many regressions in WORKSPACE mode in CI. --- internal_dev_deps.bzl | 5 ----- python/config_settings/BUILD.bazel | 9 +-------- python/private/pypi/whl_library_targets.bzl | 2 +- .../whl_library_targets_tests.bzl | 18 +++++++++--------- tests/repos/whl_with_data/BUILD.bazel | 2 +- 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/internal_dev_deps.bzl b/internal_dev_deps.bzl index 2206197f66..50277ad4ad 100644 --- a/internal_dev_deps.bzl +++ b/internal_dev_deps.bzl @@ -65,11 +65,6 @@ def rules_python_internal_deps(): path = "tests/modules/another_module", ) - local_repository( - name = "whl_with_data", - path = "tests/repos/whl_with_data", - ) - http_archive( name = "bazel_skylib", sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 9ac6f5bde5..7060d50b26 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -229,7 +229,7 @@ string_flag( ) config_setting( - name = "_is_venvs_site_packages_yes", + name = "is_venvs_site_packages", flag_values = { ":venvs_site_packages": VenvsSitePackages.YES, }, @@ -237,13 +237,6 @@ config_setting( visibility = ["//visibility:public"], ) -# TODO: Remove this once external users have migrated. -alias( - name = "is_venvs_site_packages", - actual = ":_is_venvs_site_packages_yes", - visibility = ["//visibility:public"], -) - define_pypi_internal_flags( name = "define_pypi_internal_flags", ) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 1745949ed7..94bd26569a 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -43,7 +43,7 @@ _BAZEL_REPO_FILE_GLOBS = [ "WORKSPACE.bazel", ] -_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:_is_venvs_site_packages_yes") +_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:is_venvs_site_packages") def whl_library_targets_from_requires( *, diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl index 659366ff05..f3e0b26fc1 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -245,11 +245,11 @@ def _test_whl_and_library_deps_from_requires(env): env.expect.that_dict(py_library_call).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:_is_venvs_site_packages_yes"): [], + Label("//python/config_settings:is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:is_venvs_site_packages"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi//bar:pkg"] + select({ ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], @@ -259,7 +259,7 @@ def _test_whl_and_library_deps_from_requires(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:_is_venvs_site_packages_yes"): [], + Label("//python/config_settings:is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -361,11 +361,11 @@ def _test_whl_and_library_deps(env): env.expect.that_dict(py_library_calls[0]).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:_is_venvs_site_packages_yes"): [], + Label("//python/config_settings:is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:is_venvs_site_packages"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": [ "@pypi_bar_baz//:pkg", @@ -386,7 +386,7 @@ def _test_whl_and_library_deps(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:_is_venvs_site_packages_yes"): [], + Label("//python/config_settings:is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -444,11 +444,11 @@ def _test_group(env): ).contains_exactly({ "name": "_pkg", "srcs": ["site-packages/foo/srcs.py"] + select({ - Label("//python/config_settings:_is_venvs_site_packages_yes"): [], + Label("//python/config_settings:is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/pyi.pyi"], - "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:is_venvs_site_packages"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi_bar_baz//:pkg"] + select({ "@platforms//os:linux": ["@pypi_box//:pkg"], @@ -459,7 +459,7 @@ def _test_group(env): "visibility": ["@pypi__config//_groups:__pkg__"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:_is_venvs_site_packages_yes"): [], + Label("//python/config_settings:is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items diff --git a/tests/repos/whl_with_data/BUILD.bazel b/tests/repos/whl_with_data/BUILD.bazel index 7ef8ba4cd9..af49d1ebbf 100644 --- a/tests/repos/whl_with_data/BUILD.bazel +++ b/tests/repos/whl_with_data/BUILD.bazel @@ -1 +1 @@ -exports_files(glob(["**"])) +exports_files(glob(["*"])) From b35951aaf2b8868546e50d15f2b32ee1e52d43d8 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:43:07 -0700 Subject: [PATCH 13/40] fix: add bazel_skylib to pip_parse_vendored example --- examples/pip_parse_vendored/WORKSPACE | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/pip_parse_vendored/WORKSPACE b/examples/pip_parse_vendored/WORKSPACE index 5e80b4116b..d2091e38c6 100644 --- a/examples/pip_parse_vendored/WORKSPACE +++ b/examples/pip_parse_vendored/WORKSPACE @@ -7,6 +7,15 @@ local_repository( load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") +http_archive( + name = "bazel_skylib", + sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", + ], +) + py_repositories() python_register_toolchains( From 52dfac5487ed453c8537b19924308a8aa810a75e Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:43:26 -0700 Subject: [PATCH 14/40] fix: add bazel_skylib to multi_python_versions and pip_parse examples --- examples/multi_python_versions/WORKSPACE | 9 +++++++++ examples/pip_parse/WORKSPACE | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/examples/multi_python_versions/WORKSPACE b/examples/multi_python_versions/WORKSPACE index 0b6b8a0cbf..fd946428bb 100644 --- a/examples/multi_python_versions/WORKSPACE +++ b/examples/multi_python_versions/WORKSPACE @@ -7,6 +7,15 @@ local_repository( load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_multi_toolchains") +http_archive( + name = "bazel_skylib", + sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", + ], +) + py_repositories() default_python_version = "3.10" diff --git a/examples/pip_parse/WORKSPACE b/examples/pip_parse/WORKSPACE index e0d60af9ff..74a6e78c12 100644 --- a/examples/pip_parse/WORKSPACE +++ b/examples/pip_parse/WORKSPACE @@ -7,6 +7,15 @@ local_repository( load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") +http_archive( + name = "bazel_skylib", + sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", + ], +) + py_repositories() python_register_toolchains( From 45611a56386d0ca3a1e8fd5b9dca4e6697abff66 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:45:06 -0700 Subject: [PATCH 15/40] docs: add DATA field to VenvSymlinkKind docstring --- python/private/py_info.bzl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/private/py_info.bzl b/python/private/py_info.bzl index 28056f906c..551e0bb48c 100644 --- a/python/private/py_info.bzl +++ b/python/private/py_info.bzl @@ -37,6 +37,12 @@ def _VenvSymlinkKind_typedef(): Indicates to create paths under the venv's include directory. ::: + + :::{field} DATA + :type: object + + Indicates to create paths under the venv's data directory. + ::: """ # buildifier: disable=name-conventions From fd6cda6412e30e3eff53fe5223cc3eac1aeb0d2f Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:48:42 -0700 Subject: [PATCH 16/40] fix: undefined data_arg in whl_library_targets.bzl --- python/private/pypi/whl_library_targets.bzl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 94bd26569a..2aa296b6bc 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -365,6 +365,8 @@ def whl_library_targets( exclude = _data_exclude, allow_empty = True, ) + + data_param = data data = data + site_packages_data + select({ _IS_VENV_SITE_PACKAGES_YES: [DATA_LABEL], "//conditions:default": [], @@ -379,7 +381,7 @@ def whl_library_targets( generated_namespace_package_files = select({ _IS_VENV_SITE_PACKAGES_YES: [], "//conditions:default": rules.create_inits( - srcs = srcs + site_packages_data + pyi_srcs, + srcs = srcs + data_param + site_packages_data + pyi_srcs, ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so. root = "site-packages", ), From 958e61e57058a191d5b4a6961e6815e4d9586415 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:51:47 -0700 Subject: [PATCH 17/40] fix: robustness in venvs_site_packages_libs_test for Windows paths --- tests/venv_site_packages_libs/bin.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 24989cedcc..889c030514 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -112,14 +112,21 @@ def test_whl_with_data_included(self): venv_root = Path(self.venv) is_windows = sys.platform == "win32" - bin_dir_name = "Scripts" if is_windows else "bin" - include_dir_name = "Include" if is_windows else "include" + + # On Windows, rules_python usually uses Scripts, but some environments or + # configurations might use bin. + if is_windows: + bin_dir_name = "Scripts" if (venv_root / "Scripts").exists() else "bin" + include_dir_name = "Include" if (venv_root / "Include").exists() else "include" + else: + bin_dir_name = "bin" + include_dir_name = "include" # data data_data_file = venv_root / "data" / "whl_with_data" / "data_data_file.txt" self.assertTrue( data_data_file.exists(), - f"Expected {data_data_file} to exist. venv_root contents: {list(venv_root.iterdir())}. os.name={os.name}, sys.platform={sys.platform}", + f"Expected {data_data_file} to exist. venv_root contents: {list(venv_root.iterdir()) if venv_root.exists() else 'N/A'}. os.name={os.name}, sys.platform={sys.platform}", ) # scripts From 194693cc919c82f5b35047470e868b0e11964727 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 15:54:38 -0700 Subject: [PATCH 18/40] fix: make bin/s3cmd expectation conditional in pip_parse_test.py Also revert redundant bazel_skylib additions to example WORKSPACE files. --- examples/multi_python_versions/WORKSPACE | 9 --------- examples/pip_parse/WORKSPACE | 9 --------- examples/pip_parse/pip_parse_test.py | 24 +++++++++++++----------- examples/pip_parse_vendored/WORKSPACE | 9 --------- 4 files changed, 13 insertions(+), 38 deletions(-) diff --git a/examples/multi_python_versions/WORKSPACE b/examples/multi_python_versions/WORKSPACE index fd946428bb..0b6b8a0cbf 100644 --- a/examples/multi_python_versions/WORKSPACE +++ b/examples/multi_python_versions/WORKSPACE @@ -7,15 +7,6 @@ local_repository( load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_multi_toolchains") -http_archive( - name = "bazel_skylib", - sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", - ], -) - py_repositories() default_python_version = "3.10" diff --git a/examples/pip_parse/WORKSPACE b/examples/pip_parse/WORKSPACE index 74a6e78c12..e0d60af9ff 100644 --- a/examples/pip_parse/WORKSPACE +++ b/examples/pip_parse/WORKSPACE @@ -7,15 +7,6 @@ local_repository( load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") -http_archive( - name = "bazel_skylib", - sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", - ], -) - py_repositories() python_register_toolchains( diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index 1ba29713d2..1eebedcb55 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -52,17 +52,19 @@ def test_data(self): self.assertIsNotNone(actual) actual = self._remove_leading_dirs(actual.split(" ")) - self.assertListEqual( - actual, - [ - "bin/s3cmd", - "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", - ], - ) + expected = [ + "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", + ] + # In bzlmod mode with venvs_site_packages=yes, we include bin/ and include/ + # in the data target. + if "bin/s3cmd" in actual: + expected.insert(0, "bin/s3cmd") + + self.assertListEqual(actual, expected) def test_dist_info(self): actual = os.environ.get("WHEEL_DIST_INFO_CONTENTS") diff --git a/examples/pip_parse_vendored/WORKSPACE b/examples/pip_parse_vendored/WORKSPACE index d2091e38c6..5e80b4116b 100644 --- a/examples/pip_parse_vendored/WORKSPACE +++ b/examples/pip_parse_vendored/WORKSPACE @@ -7,15 +7,6 @@ local_repository( load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") -http_archive( - name = "bazel_skylib", - sha256 = "6e78f0e57de26801f6f564fa7c4a48dc8b36873e416257a92bbb0937eeac8446", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.2/bazel-skylib-1.8.2.tar.gz", - ], -) - py_repositories() python_register_toolchains( From 82b9acc9b51f1137c983800c18fbc9bf94600664 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:01:32 -0700 Subject: [PATCH 19/40] refactor: rename is_venvs_site_packages to _is_venvs_site_packages The original target was intended to be internal-only, so it has been renamed and all references updated. No alias was added as per instructions. --- python/config_settings/BUILD.bazel | 2 +- python/private/pypi/whl_library_targets.bzl | 2 +- .../whl_library_targets_tests.bzl | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 7060d50b26..7f8b6b9734 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -229,7 +229,7 @@ string_flag( ) config_setting( - name = "is_venvs_site_packages", + name = "_is_venvs_site_packages", flag_values = { ":venvs_site_packages": VenvsSitePackages.YES, }, diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 2aa296b6bc..7504e45d74 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -43,7 +43,7 @@ _BAZEL_REPO_FILE_GLOBS = [ "WORKSPACE.bazel", ] -_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:is_venvs_site_packages") +_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:_is_venvs_site_packages") def whl_library_targets_from_requires( *, diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl index f3e0b26fc1..25e4bc73aa 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -245,11 +245,11 @@ def _test_whl_and_library_deps_from_requires(env): env.expect.that_dict(py_library_call).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:is_venvs_site_packages"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi//bar:pkg"] + select({ ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], @@ -259,7 +259,7 @@ def _test_whl_and_library_deps_from_requires(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -361,11 +361,11 @@ def _test_whl_and_library_deps(env): env.expect.that_dict(py_library_calls[0]).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:is_venvs_site_packages"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": [ "@pypi_bar_baz//:pkg", @@ -386,7 +386,7 @@ def _test_whl_and_library_deps(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -444,11 +444,11 @@ def _test_group(env): ).contains_exactly({ "name": "_pkg", "srcs": ["site-packages/foo/srcs.py"] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/pyi.pyi"], - "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:is_venvs_site_packages"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi_bar_baz//:pkg"] + select({ "@platforms//os:linux": ["@pypi_box//:pkg"], @@ -459,7 +459,7 @@ def _test_group(env): "visibility": ["@pypi__config//_groups:__pkg__"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items From dd2b0b3063c7382a73b9840456d7a91bbbf7c3c4 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:05:52 -0700 Subject: [PATCH 20/40] pass create_inits() non-selet value, add select value afterwards --- python/private/pypi/whl_library_targets.bzl | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 7504e45d74..a14c6c4ff8 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -360,18 +360,12 @@ def whl_library_targets( if item not in _data_exclude: _data_exclude.append(item) - site_packages_data = native.glob( + data = data + native.glob( ["site-packages/**/*"], exclude = _data_exclude, allow_empty = True, ) - data_param = data - data = data + site_packages_data + select({ - _IS_VENV_SITE_PACKAGES_YES: [DATA_LABEL], - "//conditions:default": [], - }) - pyi_srcs = native.glob( ["site-packages/**/*.pyi"], allow_empty = True, @@ -381,7 +375,7 @@ def whl_library_targets( generated_namespace_package_files = select({ _IS_VENV_SITE_PACKAGES_YES: [], "//conditions:default": rules.create_inits( - srcs = srcs + data_param + site_packages_data + pyi_srcs, + srcs = srcs + data + pyi_srcs, ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so. root = "site-packages", ), @@ -389,6 +383,13 @@ def whl_library_targets( namespace_package_files += generated_namespace_package_files srcs = srcs + generated_namespace_package_files + # This must be doe after the above because create_inits() is macro-phase, + # so can't handle select() values. + data = data + select({ + _IS_VENV_SITE_PACKAGES_YES: [DATA_LABEL], + "//conditions:default": [], + }) + rules.py_library( name = py_library_label, srcs = srcs, From 3ed727eac22182ec16649f20b5826d20623f0c03 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:08:36 -0700 Subject: [PATCH 21/40] change test to enforce windows uses Scripts/Include in venv --- tests/venv_site_packages_libs/bin.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 889c030514..2e6419ad92 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -112,12 +112,9 @@ def test_whl_with_data_included(self): venv_root = Path(self.venv) is_windows = sys.platform == "win32" - - # On Windows, rules_python usually uses Scripts, but some environments or - # configurations might use bin. if is_windows: - bin_dir_name = "Scripts" if (venv_root / "Scripts").exists() else "bin" - include_dir_name = "Include" if (venv_root / "Include").exists() else "include" + bin_dir_name = "Scripts" + include_dir_name = "Include" else: bin_dir_name = "bin" include_dir_name = "include" From 7561c72667853a433b5e02d3ad333dddb6811b8e Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:20:21 -0700 Subject: [PATCH 22/40] make pip_parse_test.py work with venv_site_packages --- examples/pip_parse/BUILD.bazel | 7 ++++++- examples/pip_parse/pip_parse_test.py | 13 +++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/examples/pip_parse/BUILD.bazel b/examples/pip_parse/BUILD.bazel index 37a25fe873..ebc2057623 100644 --- a/examples/pip_parse/BUILD.bazel +++ b/examples/pip_parse/BUILD.bazel @@ -2,6 +2,7 @@ load("@rules_python//python:pip.bzl", "compile_pip_requirements") load("@rules_python//python:py_binary.bzl", "py_binary") load("@rules_python//python:py_test.bzl", "py_test") load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary") +load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility # 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). @@ -75,10 +76,14 @@ py_test( "@pypi//s3cmd:data", ], env = { + "BZLMOD_ENABLED": "1" if BZLMOD_ENABLED else "0", "WHEEL_DATA_CONTENTS": "$(rootpaths @pypi//s3cmd:data)", "WHEEL_DIST_INFO_CONTENTS": "$(rootpaths @pypi//requests:dist_info)", "YAMLLINT_ENTRY_POINT": "$(rlocationpath :yamllint)", - }, + } | select({ + "@rules_python//python/config_settings:_is_venvs_site_packages": {"VENVS_SITE_PACKAGES": "1"}, + "//conditions:default": {"VENVS_SITE_PACKAGES": "0"}, + }), deps = [ "@pypi//libclang", "@rules_python//python/runfiles", diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index 1eebedcb55..ea18e64095 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -30,6 +30,10 @@ def _remove_leading_dirs(self, paths): # to normalize what workspace and bzlmod produce. return ["/".join(v.split("/")[2:]) for v in paths] + def test_environment_variables(self): + self.assertIn("BZLMOD_ENABLED", os.environ) + self.assertIn("VENVS_SITE_PACKAGES", os.environ) + def test_entry_point(self): entry_point_path = os.environ.get("YAMLLINT_ENTRY_POINT") self.assertIsNotNone(entry_point_path) @@ -48,6 +52,11 @@ def test_entry_point(self): self.assertEqual(proc.stdout.decode("utf-8").strip(), "yamllint 1.28.0") def test_data(self): + is_bzlmod = os.environ.get("BZLMOD_ENABLED") == "1" + # The env var name in the BUILD file is VENVS_SITE_PACKAGES (plural) + # to match the flag name. + is_venvs_site_packages = os.environ.get("VENVS_SITE_PACKAGES") == "1" + actual = os.environ.get("WHEEL_DATA_CONTENTS") self.assertIsNotNone(actual) actual = self._remove_leading_dirs(actual.split(" ")) @@ -59,9 +68,9 @@ def test_data(self): "data/share/doc/packages/s3cmd/README.md", "data/share/man/man1/s3cmd.1", ] - # In bzlmod mode with venvs_site_packages=yes, we include bin/ and include/ + # In bzlmod mode with venvs_site_packages=yes, we include bin/ and include/ # in the data target. - if "bin/s3cmd" in actual: + if (is_bzlmod and is_venvs_site_packages): expected.insert(0, "bin/s3cmd") self.assertListEqual(actual, expected) From 24a94a2abf3acbaaad62a06314998e4f0f6ed513 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:25:53 -0700 Subject: [PATCH 23/40] add second wheel with data to test merging/overlap. rename first --- MODULE.bazel | 3 +- python/private/internal_dev_deps.bzl | 23 +++++--- tests/repos/whl_with_data/WORKSPACE | 1 - .../whl_with_data-1.0.dist-info/RECORD | 6 --- .../BUILD.bazel | 0 .../data/whl_with_data1}/data_data_file.txt | 0 .../headers/whl_with_data1}/header_file.h | 0 .../platlib/whl_with_data1}/platlib_file.txt | 0 .../purelib/whl_with_data1}/__init__.py | 0 .../purelib/whl_with_data1}/data_file.txt | 0 .../scripts/whl_script.sh | 0 .../whl_with_data1-1.0.dist-info}/METADATA | 2 +- .../whl_with_data1-1.0.dist-info/RECORD | 6 +++ .../whl_with_data1-1.0.dist-info}/WHEEL | 0 tests/repos/whl_with_data2/BUILD.bazel | 1 + .../data/whl_with_data2/data_data_file.txt | 1 + .../headers/whl_with_data2/header_file.h | 1 + .../platlib/whl_with_data2/platlib_file.txt | 1 + .../purelib/whl_with_data2/__init__.py | 0 .../purelib/whl_with_data2/data_file.txt | 1 + .../scripts/whl_script.sh | 1 + .../whl_with_data2-1.0.dist-info/METADATA | 3 ++ .../whl_with_data2-1.0.dist-info/RECORD | 6 +++ .../whl_with_data2-1.0.dist-info/WHEEL | 1 + tests/venv_site_packages_libs/BUILD.bazel | 2 +- tests/venv_site_packages_libs/bin.py | 54 ++++++++++++++++--- 26 files changed, 90 insertions(+), 23 deletions(-) delete mode 100644 tests/repos/whl_with_data/WORKSPACE delete mode 100644 tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD rename tests/repos/{whl_with_data => whl_with_data1}/BUILD.bazel (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.data/data/whl_with_data => whl_with_data1/whl_with_data1-1.0.data/data/whl_with_data1}/data_data_file.txt (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.data/headers/whl_with_data => whl_with_data1/whl_with_data1-1.0.data/headers/whl_with_data1}/header_file.h (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data => whl_with_data1/whl_with_data1-1.0.data/platlib/whl_with_data1}/platlib_file.txt (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data => whl_with_data1/whl_with_data1-1.0.data/purelib/whl_with_data1}/__init__.py (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data => whl_with_data1/whl_with_data1-1.0.data/purelib/whl_with_data1}/data_file.txt (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.data => whl_with_data1/whl_with_data1-1.0.data}/scripts/whl_script.sh (100%) rename tests/repos/{whl_with_data/whl_with_data-1.0.dist-info => whl_with_data1/whl_with_data1-1.0.dist-info}/METADATA (62%) create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD rename tests/repos/{whl_with_data/whl_with_data-1.0.dist-info => whl_with_data1/whl_with_data1-1.0.dist-info}/WHEEL (100%) create mode 100644 tests/repos/whl_with_data2/BUILD.bazel create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/whl_with_data2/header_file.h create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/platlib/whl_with_data2/platlib_file.txt create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/__init__.py create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/data_file.txt create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/whl_script.sh create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/METADATA create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/WHEEL diff --git a/MODULE.bazel b/MODULE.bazel index ff5c369b8b..b5f67c204e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -246,7 +246,8 @@ use_repo( "somepkg_with_build_files", "whl_library_extras_direct_dep", "whl_with_build_files", - "whl_with_data", + "whl_with_data1", + "whl_with_data2", ) dev_rules_python_config = use_extension( diff --git a/python/private/internal_dev_deps.bzl b/python/private/internal_dev_deps.bzl index b615ca0099..11b020e59f 100644 --- a/python/private/internal_dev_deps.bzl +++ b/python/private/internal_dev_deps.bzl @@ -92,14 +92,25 @@ def _internal_dev_deps_impl(mctx): ) whl_from_dir_repo( - name = "whl_with_data_whl", - root = "//tests/repos/whl_with_data:BUILD.bazel", - output = "whl_with_data-1.0-any-none-any.whl", + name = "whl_with_data1_whl", + root = "//tests/repos/whl_with_data1:BUILD.bazel", + output = "whl_with_data1-1.0-any-none-any.whl", ) whl_library( - name = "whl_with_data", - whl_file = "@whl_with_data_whl//:whl_with_data-1.0-any-none-any.whl", - requirement = "whl-with-data", + name = "whl_with_data1", + whl_file = "@whl_with_data1_whl//:whl_with_data1-1.0-any-none-any.whl", + requirement = "whl-with-data1", + ) + + whl_from_dir_repo( + name = "whl_with_data2_whl", + root = "//tests/repos/whl_with_data2:BUILD.bazel", + output = "whl_with_data2-1.0-any-none-any.whl", + ) + whl_library( + name = "whl_with_data2", + whl_file = "@whl_with_data2_whl//:whl_with_data2-1.0-any-none-any.whl", + requirement = "whl-with-data2", ) _whl_library_from_dir( diff --git a/tests/repos/whl_with_data/WORKSPACE b/tests/repos/whl_with_data/WORKSPACE deleted file mode 100644 index 654876d503..0000000000 --- a/tests/repos/whl_with_data/WORKSPACE +++ /dev/null @@ -1 +0,0 @@ -workspace(name = "whl_with_data") diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD b/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD deleted file mode 100644 index 8d655b1cec..0000000000 --- a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/RECORD +++ /dev/null @@ -1,6 +0,0 @@ -whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt,sha256=123,123 -whl_with_data-1.0.data/scripts/whl_script.sh,sha256=123,123 -whl_with_data-1.0.data/headers/whl_with_data/header_file.h,sha256=123,123 -whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt,sha256=123,123 -whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt,sha256=123,123 -whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt,sha256=123,123 diff --git a/tests/repos/whl_with_data/BUILD.bazel b/tests/repos/whl_with_data1/BUILD.bazel similarity index 100% rename from tests/repos/whl_with_data/BUILD.bazel rename to tests/repos/whl_with_data1/BUILD.bazel diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.data/data/whl_with_data/data_data_file.txt rename to tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/headers/whl_with_data/header_file.h b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/whl_with_data1/header_file.h similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.data/headers/whl_with_data/header_file.h rename to tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/whl_with_data1/header_file.h diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/platlib/whl_with_data1/platlib_file.txt similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.data/platlib/whl_with_data/platlib_file.txt rename to tests/repos/whl_with_data1/whl_with_data1-1.0.data/platlib/whl_with_data1/platlib_file.txt diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/__init__.py b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/whl_with_data1/__init__.py similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/__init__.py rename to tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/whl_with_data1/__init__.py diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/whl_with_data1/data_file.txt similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.data/purelib/whl_with_data/data_file.txt rename to tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/whl_with_data1/data_file.txt diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.data/scripts/whl_script.sh b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/whl_script.sh similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.data/scripts/whl_script.sh rename to tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/whl_script.sh diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/METADATA similarity index 62% rename from tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA rename to tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/METADATA index b5ba7f8a9d..f403970d7a 100644 --- a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/METADATA +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/METADATA @@ -1,3 +1,3 @@ Metadata-Version: 2.1 -Name: whl-with-data +Name: whl-with-data1 Version: 1.0 diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD new file mode 100644 index 0000000000..72e405ffd7 --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD @@ -0,0 +1,6 @@ +whl_with_data1-1.0.data/platlib/whl_with_data1/platlib_file.txt,sha256=123,123 +whl_with_data1-1.0.data/scripts/whl_script.sh,sha256=123,123 +whl_with_data1-1.0.data/headers/whl_with_data1/header_file.h,sha256=123,123 +whl_with_data1-1.0.data/purelib/whl_with_data1/data_file.txt,sha256=123,123 +whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt,sha256=123,123 +whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt,sha256=123,123 diff --git a/tests/repos/whl_with_data/whl_with_data-1.0.dist-info/WHEEL b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/WHEEL similarity index 100% rename from tests/repos/whl_with_data/whl_with_data-1.0.dist-info/WHEEL rename to tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/WHEEL diff --git a/tests/repos/whl_with_data2/BUILD.bazel b/tests/repos/whl_with_data2/BUILD.bazel new file mode 100644 index 0000000000..af49d1ebbf --- /dev/null +++ b/tests/repos/whl_with_data2/BUILD.bazel @@ -0,0 +1 @@ +exports_files(glob(["*"])) diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt new file mode 100644 index 0000000000..39ec676600 --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt @@ -0,0 +1 @@ +from .data/data diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/whl_with_data2/header_file.h b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/whl_with_data2/header_file.h new file mode 100644 index 0000000000..59c9bf78c2 --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/whl_with_data2/header_file.h @@ -0,0 +1 @@ +from .data/headers diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/platlib/whl_with_data2/platlib_file.txt b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/platlib/whl_with_data2/platlib_file.txt new file mode 100644 index 0000000000..b27295614f --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/platlib/whl_with_data2/platlib_file.txt @@ -0,0 +1 @@ +from .data/platlib diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/__init__.py b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/data_file.txt b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/data_file.txt new file mode 100644 index 0000000000..e547fe48ed --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/purelib/whl_with_data2/data_file.txt @@ -0,0 +1 @@ +from .data diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/whl_script.sh b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/whl_script.sh new file mode 100644 index 0000000000..1a2485251c --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/whl_script.sh @@ -0,0 +1 @@ +#!/bin/sh diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/METADATA b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/METADATA new file mode 100644 index 0000000000..c762d184fb --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/METADATA @@ -0,0 +1,3 @@ +Metadata-Version: 2.1 +Name: whl-with-data2 +Version: 1.0 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD new file mode 100644 index 0000000000..a879ae0a22 --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD @@ -0,0 +1,6 @@ +whl_with_data2-1.0.data/platlib/whl_with_data2/platlib_file.txt,sha256=123,123 +whl_with_data2-1.0.data/scripts/whl_script.sh,sha256=123,123 +whl_with_data2-1.0.data/headers/whl_with_data2/header_file.h,sha256=123,123 +whl_with_data2-1.0.data/purelib/whl_with_data2/data_file.txt,sha256=123,123 +whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt,sha256=123,123 +whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt,sha256=123,123 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/WHEEL b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/WHEEL new file mode 100644 index 0000000000..a64521a1cc --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/WHEEL @@ -0,0 +1 @@ +Wheel-Version: 1.0 diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index 500388d9ad..b3c5ba6136 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -49,7 +49,7 @@ py_reconfig_test( "@other//nspkg_gamma", "@other//nspkg_single", "@other//with_external_data", - ] + (["@whl_with_data//:pkg"] if BZLMOD_ENABLED else []), + ] + (["@whl_with_data1//:pkg", "@whl_with_data2//:pkg"] if BZLMOD_ENABLED else []), ) py_reconfig_test( diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 2e6419ad92..997ecd479e 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -94,19 +94,19 @@ def test_data_from_another_pkg_is_included_via_copy_file(self): @unittest.skipIf( os.environ.get("BZLMOD_ENABLED") == "0", - "whl_with_data is only available with bzlmod", + "whl_with_data1 is only available with bzlmod", ) - def test_whl_with_data_included(self): - module = self.assert_imported_from_venv("whl_with_data") + def test_whl_with_data1_included(self): + module = self.assert_imported_from_venv("whl_with_data1") module_path = Path(module.__file__) site_packages = module_path.parent.parent # purelib - data_file = site_packages / "whl_with_data" / "data_file.txt" + data_file = site_packages / "whl_with_data1" / "data_file.txt" self.assertTrue(data_file.exists(), f"Expected {data_file} to exist") # platlib - platlib_file = site_packages / "whl_with_data" / "platlib_file.txt" + platlib_file = site_packages / "whl_with_data1" / "platlib_file.txt" self.assertTrue(platlib_file.exists(), f"Expected {platlib_file} to exist") venv_root = Path(self.venv) @@ -120,7 +120,7 @@ def test_whl_with_data_included(self): include_dir_name = "include" # data - data_data_file = venv_root / "data" / "whl_with_data" / "data_data_file.txt" + data_data_file = venv_root / "data" / "whl_with_data1" / "data_data_file.txt" self.assertTrue( data_data_file.exists(), f"Expected {data_data_file} to exist. venv_root contents: {list(venv_root.iterdir()) if venv_root.exists() else 'N/A'}. os.name={os.name}, sys.platform={sys.platform}", @@ -134,7 +134,7 @@ def test_whl_with_data_included(self): ) # headers - header_file = venv_root / include_dir_name / "whl_with_data" / "header_file.h" + header_file = venv_root / include_dir_name / "whl_with_data1" / "header_file.h" self.assertTrue( header_file.exists(), f"Expected {header_file} to exist. {include_dir_name} contents: {list((venv_root / include_dir_name).iterdir()) if (venv_root / include_dir_name).exists() else 'N/A'}", @@ -143,3 +143,43 @@ def test_whl_with_data_included(self): if __name__ == "__main__": unittest.main() + + @unittest.skipIf( + os.environ.get("BZLMOD_ENABLED") == "0", + "whl_with_data1 is only available with bzlmod", + ) + def test_whl_with_data2_included(self): + module = self.assert_imported_from_venv("whl_with_data2") + + venv_root = Path(module.__file__).parents[3] + site_packages = venv_root / "lib" / "site-packages" + + data_file = site_packages / "whl_with_data2" / "data_file.txt" + self.assertTrue(data_file.exists(), data_file) + self.assertTrue(data_file.is_file(), data_file) + + platlib_file = site_packages / "whl_with_data2" / "platlib_file.txt" + self.assertTrue(platlib_file.exists(), platlib_file) + self.assertTrue(platlib_file.is_file(), platlib_file) + + script_file = venv_root / "bin" / "whl_script.sh" + self.assertTrue(script_file.exists(), script_file) + self.assertTrue(script_file.is_file(), script_file) + + # Ensure that `data` files are unpacked in `venv/data/` + # and then linked as `venv/data/whl_with_data1/data_data_file.txt`. + data_data_file = venv_root / "data" / "whl_with_data2" / "data_data_file.txt" + self.assertTrue(data_data_file.exists(), data_data_file) + self.assertTrue(data_data_file.is_file(), data_data_file) + self.assertTrue(data_data_file.read_text() == "123\n") + + # In python versions < 3.10, the `venv/include/pythonX.Y/` dir doesn't seem to get + # created but we don't care to support dropping includes there on that + # platform. + if sys.version_info >= (3, 10): + # Include dir is `include/pythonX.Y`. + include_dir_name = f"include/python{sys.version_info.major}.{sys.version_info.minor}" + header_file = venv_root / include_dir_name / "whl_with_data2" / "header_file.h" + self.assertTrue(header_file.exists(), header_file) + self.assertTrue(header_file.is_file(), header_file) + self.assertTrue(header_file.read_text() == "123\n") From 1fabeea31c7f35f2d6757661e595b0f284469f97 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:28:11 -0700 Subject: [PATCH 24/40] format --- examples/pip_parse/pip_parse_test.py | 2 +- tests/venv_site_packages_libs/BUILD.bazel | 5 ++++- tests/venv_site_packages_libs/bin.py | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index ea18e64095..c848bcd6cc 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -70,7 +70,7 @@ def test_data(self): ] # In bzlmod mode with venvs_site_packages=yes, we include bin/ and include/ # in the data target. - if (is_bzlmod and is_venvs_site_packages): + if is_bzlmod and is_venvs_site_packages: expected.insert(0, "bin/s3cmd") self.assertListEqual(actual, expected) diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index b3c5ba6136..433a4b00b4 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -49,7 +49,10 @@ py_reconfig_test( "@other//nspkg_gamma", "@other//nspkg_single", "@other//with_external_data", - ] + (["@whl_with_data1//:pkg", "@whl_with_data2//:pkg"] if BZLMOD_ENABLED else []), + ] + ([ + "@whl_with_data1//:pkg", + "@whl_with_data2//:pkg", + ] if BZLMOD_ENABLED else []), ) py_reconfig_test( diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 997ecd479e..a40e1004cb 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -178,8 +178,12 @@ def test_whl_with_data2_included(self): # platform. if sys.version_info >= (3, 10): # Include dir is `include/pythonX.Y`. - include_dir_name = f"include/python{sys.version_info.major}.{sys.version_info.minor}" - header_file = venv_root / include_dir_name / "whl_with_data2" / "header_file.h" + include_dir_name = ( + f"include/python{sys.version_info.major}.{sys.version_info.minor}" + ) + header_file = ( + venv_root / include_dir_name / "whl_with_data2" / "header_file.h" + ) self.assertTrue(header_file.exists(), header_file) self.assertTrue(header_file.is_file(), header_file) self.assertTrue(header_file.read_text() == "123\n") From 473966b169689a01c08f44def4f050dc61f88e14 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sat, 25 Apr 2026 16:35:55 -0700 Subject: [PATCH 25/40] revert passing bzlmod/venv_site_packages to pip_parse_test. not needed because data files are always added --- examples/pip_parse/BUILD.bazel | 7 +------ examples/pip_parse/pip_parse_test.py | 14 +------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/examples/pip_parse/BUILD.bazel b/examples/pip_parse/BUILD.bazel index ebc2057623..37a25fe873 100644 --- a/examples/pip_parse/BUILD.bazel +++ b/examples/pip_parse/BUILD.bazel @@ -2,7 +2,6 @@ load("@rules_python//python:pip.bzl", "compile_pip_requirements") load("@rules_python//python:py_binary.bzl", "py_binary") load("@rules_python//python:py_test.bzl", "py_test") load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary") -load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility # 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). @@ -76,14 +75,10 @@ py_test( "@pypi//s3cmd:data", ], env = { - "BZLMOD_ENABLED": "1" if BZLMOD_ENABLED else "0", "WHEEL_DATA_CONTENTS": "$(rootpaths @pypi//s3cmd:data)", "WHEEL_DIST_INFO_CONTENTS": "$(rootpaths @pypi//requests:dist_info)", "YAMLLINT_ENTRY_POINT": "$(rlocationpath :yamllint)", - } | select({ - "@rules_python//python/config_settings:_is_venvs_site_packages": {"VENVS_SITE_PACKAGES": "1"}, - "//conditions:default": {"VENVS_SITE_PACKAGES": "0"}, - }), + }, deps = [ "@pypi//libclang", "@rules_python//python/runfiles", diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index c848bcd6cc..c532dff564 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -30,10 +30,6 @@ def _remove_leading_dirs(self, paths): # to normalize what workspace and bzlmod produce. return ["/".join(v.split("/")[2:]) for v in paths] - def test_environment_variables(self): - self.assertIn("BZLMOD_ENABLED", os.environ) - self.assertIn("VENVS_SITE_PACKAGES", os.environ) - def test_entry_point(self): entry_point_path = os.environ.get("YAMLLINT_ENTRY_POINT") self.assertIsNotNone(entry_point_path) @@ -52,26 +48,18 @@ def test_entry_point(self): self.assertEqual(proc.stdout.decode("utf-8").strip(), "yamllint 1.28.0") def test_data(self): - is_bzlmod = os.environ.get("BZLMOD_ENABLED") == "1" - # The env var name in the BUILD file is VENVS_SITE_PACKAGES (plural) - # to match the flag name. - is_venvs_site_packages = os.environ.get("VENVS_SITE_PACKAGES") == "1" - actual = os.environ.get("WHEEL_DATA_CONTENTS") self.assertIsNotNone(actual) actual = self._remove_leading_dirs(actual.split(" ")) expected = [ + "bin/s3cmd", "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", ] - # In bzlmod mode with venvs_site_packages=yes, we include bin/ and include/ - # in the data target. - if is_bzlmod and is_venvs_site_packages: - expected.insert(0, "bin/s3cmd") self.assertListEqual(actual, expected) From dd5d8c23436d9299f8db16f038485f753531c0c3 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 09:24:21 -0700 Subject: [PATCH 26/40] remove defunct comment --- python/private/pypi/whl_library_targets.bzl | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index a14c6c4ff8..c2d0801763 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -196,8 +196,6 @@ def whl_library_targets( DIST_INFO_LABEL: dict( include = ["site-packages/*.dist-info/**"], ), - - ## TO CHECK: should bin/ and include/ be part of the data target? DATA_LABEL: dict( include = ["data/**", "bin/**", "include/**"], ), From 08aeea40eb90469d85105fd58e8e0dbc41296c2c Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 09:27:39 -0700 Subject: [PATCH 27/40] (re)add _yes suffix to is_venv_site_packages config setting --- python/config_settings/BUILD.bazel | 2 +- python/private/pypi/whl_library_targets.bzl | 2 +- .../whl_library_targets_tests.bzl | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 7f8b6b9734..fc0ac51451 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -229,7 +229,7 @@ string_flag( ) config_setting( - name = "_is_venvs_site_packages", + name = "_is_venvs_site_packages_yes", flag_values = { ":venvs_site_packages": VenvsSitePackages.YES, }, diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index c2d0801763..c511d3000f 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -43,7 +43,7 @@ _BAZEL_REPO_FILE_GLOBS = [ "WORKSPACE.bazel", ] -_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:_is_venvs_site_packages") +_IS_VENV_SITE_PACKAGES_YES = Label("//python/config_settings:_is_venvs_site_packages_yes") def whl_library_targets_from_requires( *, diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl index 25e4bc73aa..659366ff05 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -245,11 +245,11 @@ def _test_whl_and_library_deps_from_requires(env): env.expect.that_dict(py_library_call).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:_is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi//bar:pkg"] + select({ ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], @@ -259,7 +259,7 @@ def _test_whl_and_library_deps_from_requires(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:_is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -361,11 +361,11 @@ def _test_whl_and_library_deps(env): env.expect.that_dict(py_library_calls[0]).contains_exactly({ "name": "pkg", "srcs": ["site-packages/foo/SRCS.py"] + select({ - Label("//python/config_settings:_is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": [ "@pypi_bar_baz//:pkg", @@ -386,7 +386,7 @@ def _test_whl_and_library_deps(env): "visibility": ["//visibility:public"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:_is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items @@ -444,11 +444,11 @@ def _test_group(env): ).contains_exactly({ "name": "_pkg", "srcs": ["site-packages/foo/srcs.py"] + select({ - Label("//python/config_settings:_is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/pyi.pyi"], - "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), "imports": ["site-packages"], "deps": ["@pypi_bar_baz//:pkg"] + select({ "@platforms//os:linux": ["@pypi_box//:pkg"], @@ -459,7 +459,7 @@ def _test_group(env): "visibility": ["@pypi__config//_groups:__pkg__"], "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), "namespace_package_files": [] + select({ - Label("//python/config_settings:_is_venvs_site_packages"): [], + Label("//python/config_settings:_is_venvs_site_packages_yes"): [], "//conditions:default": ["_create_inits_target"], }), }) # buildifier: @unsorted-dict-items From 747f7cb5d261ece1d5d55050fbf39ed99f28193e Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 09:39:52 -0700 Subject: [PATCH 28/40] add basis for data overlap test --- .../data/overlap/both.txt | 1 + .../data/overlap/data1.txt | 1 + .../whl_with_data1-1.0.dist-info/RECORD | 2 + .../data/overlap/both.txt | 1 + .../data/overlap/data2.txt | 1 + .../whl_with_data2-1.0.dist-info/RECORD | 2 + tests/venv_site_packages_libs/bin.py | 57 ++++++++++++------- 7 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/both.txt create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/data1.txt create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/both.txt create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/data2.txt diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/both.txt b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/both.txt new file mode 100644 index 0000000000..771c76ed7b --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/both.txt @@ -0,0 +1 @@ +both1 diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/data1.txt b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/data1.txt new file mode 100644 index 0000000000..d760283f59 --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/overlap/data1.txt @@ -0,0 +1 @@ +data1 diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD index 72e405ffd7..f886ae830e 100644 --- a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD @@ -4,3 +4,5 @@ whl_with_data1-1.0.data/headers/whl_with_data1/header_file.h,sha256=123,123 whl_with_data1-1.0.data/purelib/whl_with_data1/data_file.txt,sha256=123,123 whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt,sha256=123,123 whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt,sha256=123,123 +whl_with_data1-1.0.data/data/overlap/both.txt,sha256=123,123 +whl_with_data1-1.0.data/data/overlap/data1.txt,sha256=123,123 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/both.txt b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/both.txt new file mode 100644 index 0000000000..1a8aa8b533 --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/both.txt @@ -0,0 +1 @@ +both2 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/data2.txt b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/data2.txt new file mode 100644 index 0000000000..98d81a2ec6 --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/data/overlap/data2.txt @@ -0,0 +1 @@ +data2 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD index a879ae0a22..a4d7d16fd6 100644 --- a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD @@ -4,3 +4,5 @@ whl_with_data2-1.0.data/headers/whl_with_data2/header_file.h,sha256=123,123 whl_with_data2-1.0.data/purelib/whl_with_data2/data_file.txt,sha256=123,123 whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt,sha256=123,123 whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt,sha256=123,123 +whl_with_data2-1.0.data/data/overlap/both.txt,sha256=123,123 +whl_with_data2-1.0.data/data/overlap/data2.txt,sha256=123,123 diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index a40e1004cb..da854b747c 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -141,8 +141,7 @@ def test_whl_with_data1_included(self): ) -if __name__ == "__main__": - unittest.main() + @unittest.skipIf( os.environ.get("BZLMOD_ENABLED") == "0", @@ -151,8 +150,9 @@ def test_whl_with_data1_included(self): def test_whl_with_data2_included(self): module = self.assert_imported_from_venv("whl_with_data2") - venv_root = Path(module.__file__).parents[3] - site_packages = venv_root / "lib" / "site-packages" + module_path = Path(module.__file__) + site_packages = module_path.parent.parent + venv_root = Path(self.venv) data_file = site_packages / "whl_with_data2" / "data_file.txt" self.assertTrue(data_file.exists(), data_file) @@ -171,19 +171,36 @@ def test_whl_with_data2_included(self): data_data_file = venv_root / "data" / "whl_with_data2" / "data_data_file.txt" self.assertTrue(data_data_file.exists(), data_data_file) self.assertTrue(data_data_file.is_file(), data_data_file) - self.assertTrue(data_data_file.read_text() == "123\n") - - # In python versions < 3.10, the `venv/include/pythonX.Y/` dir doesn't seem to get - # created but we don't care to support dropping includes there on that - # platform. - if sys.version_info >= (3, 10): - # Include dir is `include/pythonX.Y`. - include_dir_name = ( - f"include/python{sys.version_info.major}.{sys.version_info.minor}" - ) - header_file = ( - venv_root / include_dir_name / "whl_with_data2" / "header_file.h" - ) - self.assertTrue(header_file.exists(), header_file) - self.assertTrue(header_file.is_file(), header_file) - self.assertTrue(header_file.read_text() == "123\n") + + + is_windows = sys.platform == "win32" + if is_windows: + include_dir_name = "Include" + else: + include_dir_name = "include" + + header_file = ( + venv_root / include_dir_name / "whl_with_data2" / "header_file.h" + ) + self.assertTrue(header_file.exists(), header_file) + self.assertTrue(header_file.is_file(), header_file) + + + @unittest.skipIf( + os.environ.get("BZLMOD_ENABLED") == "0", + "whl_with_data is only available with bzlmod", + ) + def test_whl_with_data_overlap(self): + venv_root = Path(self.venv) + + overlap_both = venv_root / "data" / "overlap" / "both.txt" + self.assertTrue(overlap_both.exists(), f"Expected {overlap_both} to exist") + + overlap_data1 = venv_root / "data" / "overlap" / "data1.txt" + self.assertTrue(overlap_data1.exists(), f"Expected {overlap_data1} to exist") + + overlap_data2 = venv_root / "data" / "overlap" / "data2.txt" + self.assertTrue(overlap_data2.exists(), f"Expected {overlap_data2} to exist") + +if __name__ == "__main__": + unittest.main() From 03da47f61c1d6d3dde5f51a8911a988539f63fdf Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 09:54:58 -0700 Subject: [PATCH 29/40] add overlap tests for include, bin; cleanup test --- .../headers/overlap/both.h | 1 + .../headers/overlap/header1.h | 1 + .../scripts/overlap/both.sh | 1 + .../scripts/overlap/script1.sh | 1 + .../whl_with_data1-1.0.dist-info/RECORD | 4 + .../headers/overlap/both.h | 1 + .../headers/overlap/header2.h | 1 + .../scripts/overlap/both.sh | 1 + .../scripts/overlap/script2.sh | 1 + .../whl_with_data2-1.0.dist-info/RECORD | 4 + tests/venv_site_packages_libs/bin.py | 103 ++++++++---------- 11 files changed, 60 insertions(+), 59 deletions(-) create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/both.h create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/header1.h create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/both.sh create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/script1.sh create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/both.h create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/header2.h create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/both.sh create mode 100644 tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/script2.sh diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/both.h b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/both.h new file mode 100644 index 0000000000..49f33a8c6e --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/both.h @@ -0,0 +1 @@ +both diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/header1.h b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/header1.h new file mode 100644 index 0000000000..412e9ed7df --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/overlap/header1.h @@ -0,0 +1 @@ +header1 diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/both.sh b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/both.sh new file mode 100644 index 0000000000..49f33a8c6e --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/both.sh @@ -0,0 +1 @@ +both diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/script1.sh b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/script1.sh new file mode 100644 index 0000000000..4d68a2e3e0 --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/overlap/script1.sh @@ -0,0 +1 @@ +script1 diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD index f886ae830e..d0eead551d 100644 --- a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD @@ -6,3 +6,7 @@ whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt,sha256=123,123 whl_with_data1-1.0.data/data/whl_with_data1/data_data_file.txt,sha256=123,123 whl_with_data1-1.0.data/data/overlap/both.txt,sha256=123,123 whl_with_data1-1.0.data/data/overlap/data1.txt,sha256=123,123 +whl_with_data1-1.0.data/scripts/overlap/both.sh,sha256=123,123 +whl_with_data1-1.0.data/scripts/overlap/script1.sh,sha256=123,123 +whl_with_data1-1.0.data/headers/overlap/both.h,sha256=123,123 +whl_with_data1-1.0.data/headers/overlap/header1.h,sha256=123,123 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/both.h b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/both.h new file mode 100644 index 0000000000..49f33a8c6e --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/both.h @@ -0,0 +1 @@ +both diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/header2.h b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/header2.h new file mode 100644 index 0000000000..da0a719745 --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/headers/overlap/header2.h @@ -0,0 +1 @@ +header2 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/both.sh b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/both.sh new file mode 100644 index 0000000000..49f33a8c6e --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/both.sh @@ -0,0 +1 @@ +both diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/script2.sh b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/script2.sh new file mode 100644 index 0000000000..026ed8b62a --- /dev/null +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.data/scripts/overlap/script2.sh @@ -0,0 +1 @@ +script2 diff --git a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD index a4d7d16fd6..5eeb915ba7 100644 --- a/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD +++ b/tests/repos/whl_with_data2/whl_with_data2-1.0.dist-info/RECORD @@ -6,3 +6,7 @@ whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt,sha256=123,123 whl_with_data2-1.0.data/data/whl_with_data2/data_data_file.txt,sha256=123,123 whl_with_data2-1.0.data/data/overlap/both.txt,sha256=123,123 whl_with_data2-1.0.data/data/overlap/data2.txt,sha256=123,123 +whl_with_data2-1.0.data/scripts/overlap/both.sh,sha256=123,123 +whl_with_data2-1.0.data/scripts/overlap/script2.sh,sha256=123,123 +whl_with_data2-1.0.data/headers/overlap/both.h,sha256=123,123 +whl_with_data2-1.0.data/headers/overlap/header2.h,sha256=123,123 diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index da854b747c..b1796b6c2a 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -10,7 +10,22 @@ def setUp(self): super().setUp() if sys.prefix == sys.base_prefix: raise AssertionError("Not running under a venv") - self.venv = sys.prefix + self.venv = Path(sys.prefix) + + is_windows = sys.platform == "win32" + if is_windows: + self.bin_dir_name = Path("Scripts") + self.include_dir_name = Path("Include") + else: + self.bin_dir_name = Path("bin") + self.include_dir_name = Path("include") + + def assert_venv_path_exists(self, rel_path): + path = self.venv / rel_path + self.assertTrue( + path.exists(), + f"Expected {path} to exist. {path.parent.name} contents: {list(path.parent.iterdir()) if path.parent.exists() else 'N/A'}", + ) def assert_imported_from_venv(self, module_name): module = importlib.import_module(module_name) @@ -21,7 +36,7 @@ def assert_imported_from_venv(self, module_name): + f"__file__ set, but got None. {module=}", ) self.assertTrue( - module.__file__.startswith(self.venv), + module.__file__.startswith(str(self.venv)), f"\n{module_name} was imported, but not from the venv.\n" + f" venv: {self.venv}\n" + f"module file: {module.__file__}\n" @@ -101,44 +116,25 @@ def test_whl_with_data1_included(self): module_path = Path(module.__file__) site_packages = module_path.parent.parent + site_packages_rel = site_packages.relative_to(self.venv) # purelib - data_file = site_packages / "whl_with_data1" / "data_file.txt" - self.assertTrue(data_file.exists(), f"Expected {data_file} to exist") + self.assert_venv_path_exists(site_packages_rel / "whl_with_data1/data_file.txt") # platlib - platlib_file = site_packages / "whl_with_data1" / "platlib_file.txt" - self.assertTrue(platlib_file.exists(), f"Expected {platlib_file} to exist") + self.assert_venv_path_exists(site_packages_rel / "whl_with_data1/platlib_file.txt") + + venv_root = self.venv - venv_root = Path(self.venv) - is_windows = sys.platform == "win32" - if is_windows: - bin_dir_name = "Scripts" - include_dir_name = "Include" - else: - bin_dir_name = "bin" - include_dir_name = "include" # data - data_data_file = venv_root / "data" / "whl_with_data1" / "data_data_file.txt" - self.assertTrue( - data_data_file.exists(), - f"Expected {data_data_file} to exist. venv_root contents: {list(venv_root.iterdir()) if venv_root.exists() else 'N/A'}. os.name={os.name}, sys.platform={sys.platform}", - ) + self.assert_venv_path_exists("data/whl_with_data1/data_data_file.txt") # scripts - script_file = venv_root / bin_dir_name / "whl_script.sh" - self.assertTrue( - script_file.exists(), - f"Expected {script_file} to exist. {bin_dir_name} contents: {list((venv_root / bin_dir_name).iterdir()) if (venv_root / bin_dir_name).exists() else 'N/A'}", - ) + self.assert_venv_path_exists(self.bin_dir_name / "whl_script.sh") # headers - header_file = venv_root / include_dir_name / "whl_with_data1" / "header_file.h" - self.assertTrue( - header_file.exists(), - f"Expected {header_file} to exist. {include_dir_name} contents: {list((venv_root / include_dir_name).iterdir()) if (venv_root / include_dir_name).exists() else 'N/A'}", - ) + self.assert_venv_path_exists(self.include_dir_name / "whl_with_data1/header_file.h") @@ -152,38 +148,24 @@ def test_whl_with_data2_included(self): module_path = Path(module.__file__) site_packages = module_path.parent.parent - venv_root = Path(self.venv) + venv_root = self.venv + + site_packages_rel = site_packages.relative_to(self.venv) + self.assert_venv_path_exists(site_packages_rel / "whl_with_data2/data_file.txt") + - data_file = site_packages / "whl_with_data2" / "data_file.txt" - self.assertTrue(data_file.exists(), data_file) - self.assertTrue(data_file.is_file(), data_file) + self.assert_venv_path_exists(self.bin_dir_name / "whl_script.sh") - platlib_file = site_packages / "whl_with_data2" / "platlib_file.txt" - self.assertTrue(platlib_file.exists(), platlib_file) - self.assertTrue(platlib_file.is_file(), platlib_file) - script_file = venv_root / "bin" / "whl_script.sh" - self.assertTrue(script_file.exists(), script_file) - self.assertTrue(script_file.is_file(), script_file) # Ensure that `data` files are unpacked in `venv/data/` # and then linked as `venv/data/whl_with_data1/data_data_file.txt`. - data_data_file = venv_root / "data" / "whl_with_data2" / "data_data_file.txt" - self.assertTrue(data_data_file.exists(), data_data_file) - self.assertTrue(data_data_file.is_file(), data_data_file) + self.assert_venv_path_exists("data/whl_with_data2/data_data_file.txt") - is_windows = sys.platform == "win32" - if is_windows: - include_dir_name = "Include" - else: - include_dir_name = "include" - header_file = ( - venv_root / include_dir_name / "whl_with_data2" / "header_file.h" - ) - self.assertTrue(header_file.exists(), header_file) - self.assertTrue(header_file.is_file(), header_file) + + self.assert_venv_path_exists(self.include_dir_name / "whl_with_data2/header_file.h") @unittest.skipIf( @@ -191,16 +173,19 @@ def test_whl_with_data2_included(self): "whl_with_data is only available with bzlmod", ) def test_whl_with_data_overlap(self): - venv_root = Path(self.venv) + self.assert_venv_path_exists("data/overlap/both.txt") + self.assert_venv_path_exists("data/overlap/data1.txt") + self.assert_venv_path_exists("data/overlap/data2.txt") + - overlap_both = venv_root / "data" / "overlap" / "both.txt" - self.assertTrue(overlap_both.exists(), f"Expected {overlap_both} to exist") - overlap_data1 = venv_root / "data" / "overlap" / "data1.txt" - self.assertTrue(overlap_data1.exists(), f"Expected {overlap_data1} to exist") + self.assert_venv_path_exists(self.bin_dir_name / "overlap/both.sh") + self.assert_venv_path_exists(self.bin_dir_name / "overlap/script1.sh") + self.assert_venv_path_exists(self.bin_dir_name / "overlap/script2.sh") - overlap_data2 = venv_root / "data" / "overlap" / "data2.txt" - self.assertTrue(overlap_data2.exists(), f"Expected {overlap_data2} to exist") + self.assert_venv_path_exists(self.include_dir_name / "overlap/both.h") + self.assert_venv_path_exists(self.include_dir_name / "overlap/header1.h") + self.assert_venv_path_exists(self.include_dir_name / "overlap/header2.h") if __name__ == "__main__": unittest.main() From de2a11fe0a95d840e02353debd2b28c361b7e222 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 10:01:19 -0700 Subject: [PATCH 30/40] format --- tests/venv_site_packages_libs/bin.py | 58 +++++++++------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index b1796b6c2a..1c78a75878 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -1,6 +1,7 @@ import importlib import os import sys +import sysconfig import unittest from pathlib import Path @@ -11,6 +12,7 @@ def setUp(self): if sys.prefix == sys.base_prefix: raise AssertionError("Not running under a venv") self.venv = Path(sys.prefix) + self.site_packages = Path(sysconfig.get_paths()["purelib"]) is_windows = sys.platform == "win32" if is_windows: @@ -64,12 +66,8 @@ def test_imported_from_venv(self): def test_data_is_included(self): self.assert_imported_from_venv("simple") module = importlib.import_module("simple") - module_path = Path(module.__file__) - - site_packages = module_path.parent.parent - # Ensure that packages from simple v1 are not present - files = [p.name for p in site_packages.glob("*")] + files = [p.name for p in self.site_packages.glob("*")] self.assertIn("simple_v1_extras", files) def test_override_pkg(self): @@ -83,27 +81,21 @@ def test_override_pkg(self): def test_dirs_from_replaced_package_are_not_present(self): self.assert_imported_from_venv("simple") module = importlib.import_module("simple") - module_path = Path(module.__file__) - - site_packages = module_path.parent.parent - dist_info_dirs = [p.name for p in site_packages.glob("simple*.dist-info")] + dist_info_dirs = [p.name for p in self.site_packages.glob("simple*.dist-info")] self.assertEqual( ["simple-1.0.0.dist-info"], dist_info_dirs, ) # Ensure that packages from simple v1 are not present - files = [p.name for p in site_packages.glob("*")] + files = [p.name for p in self.site_packages.glob("*")] self.assertNotIn("simple.libs", files) def test_data_from_another_pkg_is_included_via_copy_file(self): self.assert_imported_from_venv("simple") module = importlib.import_module("simple") - module_path = Path(module.__file__) - - site_packages = module_path.parent.parent # Ensure that packages from simple v1 are not present - d = site_packages / "external_data" + d = self.site_packages / "external_data" files = [p.name for p in d.glob("*")] self.assertIn("another_module_data.txt", files) @@ -113,20 +105,17 @@ def test_data_from_another_pkg_is_included_via_copy_file(self): ) def test_whl_with_data1_included(self): module = self.assert_imported_from_venv("whl_with_data1") - module_path = Path(module.__file__) - site_packages = module_path.parent.parent - - site_packages_rel = site_packages.relative_to(self.venv) + site_packages_rel = self.site_packages.relative_to(self.venv) # purelib self.assert_venv_path_exists(site_packages_rel / "whl_with_data1/data_file.txt") # platlib - self.assert_venv_path_exists(site_packages_rel / "whl_with_data1/platlib_file.txt") + self.assert_venv_path_exists( + site_packages_rel / "whl_with_data1/platlib_file.txt" + ) venv_root = self.venv - - # data self.assert_venv_path_exists("data/whl_with_data1/data_data_file.txt") @@ -134,10 +123,9 @@ def test_whl_with_data1_included(self): self.assert_venv_path_exists(self.bin_dir_name / "whl_script.sh") # headers - self.assert_venv_path_exists(self.include_dir_name / "whl_with_data1/header_file.h") - - - + self.assert_venv_path_exists( + self.include_dir_name / "whl_with_data1/header_file.h" + ) @unittest.skipIf( os.environ.get("BZLMOD_ENABLED") == "0", @@ -146,27 +134,18 @@ def test_whl_with_data1_included(self): def test_whl_with_data2_included(self): module = self.assert_imported_from_venv("whl_with_data2") - module_path = Path(module.__file__) - site_packages = module_path.parent.parent - venv_root = self.venv - - site_packages_rel = site_packages.relative_to(self.venv) + site_packages_rel = self.site_packages.relative_to(self.venv) self.assert_venv_path_exists(site_packages_rel / "whl_with_data2/data_file.txt") - self.assert_venv_path_exists(self.bin_dir_name / "whl_script.sh") - - # Ensure that `data` files are unpacked in `venv/data/` # and then linked as `venv/data/whl_with_data1/data_data_file.txt`. self.assert_venv_path_exists("data/whl_with_data2/data_data_file.txt") - - - - self.assert_venv_path_exists(self.include_dir_name / "whl_with_data2/header_file.h") - + self.assert_venv_path_exists( + self.include_dir_name / "whl_with_data2/header_file.h" + ) @unittest.skipIf( os.environ.get("BZLMOD_ENABLED") == "0", @@ -177,8 +156,6 @@ def test_whl_with_data_overlap(self): self.assert_venv_path_exists("data/overlap/data1.txt") self.assert_venv_path_exists("data/overlap/data2.txt") - - self.assert_venv_path_exists(self.bin_dir_name / "overlap/both.sh") self.assert_venv_path_exists(self.bin_dir_name / "overlap/script1.sh") self.assert_venv_path_exists(self.bin_dir_name / "overlap/script2.sh") @@ -187,5 +164,6 @@ def test_whl_with_data_overlap(self): self.assert_venv_path_exists(self.include_dir_name / "overlap/header1.h") self.assert_venv_path_exists(self.include_dir_name / "overlap/header2.h") + if __name__ == "__main__": unittest.main() From 82e9e2a0836b466b669b4acecad1727312152422 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 10:30:14 -0700 Subject: [PATCH 31/40] make tests pass with workspace --- internal_dev_setup.bzl | 24 +++++++++++++++++++++++ tests/venv_site_packages_libs/BUILD.bazel | 4 ++-- tests/venv_site_packages_libs/bin.py | 12 ------------ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/internal_dev_setup.bzl b/internal_dev_setup.bzl index c37c59a5da..a72a014525 100644 --- a/internal_dev_setup.bzl +++ b/internal_dev_setup.bzl @@ -26,6 +26,8 @@ load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS") load("//python/private:pythons_hub.bzl", "hub_repo") # buildifier: disable=bzl-visibility load("//python/private:runtime_env_repo.bzl", "runtime_env_repo") # buildifier: disable=bzl-visibility load("//python/private/pypi:deps.bzl", "pypi_deps") # buildifier: disable=bzl-visibility +load("//python/private/pypi:whl_library.bzl", "whl_library") +load("//tests/support/whl_from_dir:whl_from_dir_repo.bzl", "whl_from_dir_repo") def rules_python_internal_setup(): """Setup for development and testing of rules_python itself.""" @@ -59,3 +61,25 @@ def rules_python_internal_setup(): bazel_features_deps() rules_shell_dependencies() rules_shell_toolchains() + + whl_from_dir_repo( + name = "whl_with_data1_whl", + root = "//tests/repos/whl_with_data1:BUILD.bazel", + output = "whl_with_data1-1.0-any-none-any.whl", + ) + whl_library( + name = "whl_with_data1", + whl_file = "@whl_with_data1_whl//:whl_with_data1-1.0-any-none-any.whl", + requirement = "whl-with-data1", + ) + + whl_from_dir_repo( + name = "whl_with_data2_whl", + root = "//tests/repos/whl_with_data2:BUILD.bazel", + output = "whl_with_data2-1.0-any-none-any.whl", + ) + whl_library( + name = "whl_with_data2", + whl_file = "@whl_with_data2_whl//:whl_with_data2-1.0-any-none-any.whl", + requirement = "whl-with-data2", + ) diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index 433a4b00b4..bc187b435a 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -49,10 +49,10 @@ py_reconfig_test( "@other//nspkg_gamma", "@other//nspkg_single", "@other//with_external_data", - ] + ([ + ] + [ "@whl_with_data1//:pkg", "@whl_with_data2//:pkg", - ] if BZLMOD_ENABLED else []), + ], ) py_reconfig_test( diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 1c78a75878..1abe90d157 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -99,10 +99,6 @@ def test_data_from_another_pkg_is_included_via_copy_file(self): files = [p.name for p in d.glob("*")] self.assertIn("another_module_data.txt", files) - @unittest.skipIf( - os.environ.get("BZLMOD_ENABLED") == "0", - "whl_with_data1 is only available with bzlmod", - ) def test_whl_with_data1_included(self): module = self.assert_imported_from_venv("whl_with_data1") site_packages_rel = self.site_packages.relative_to(self.venv) @@ -127,10 +123,6 @@ def test_whl_with_data1_included(self): self.include_dir_name / "whl_with_data1/header_file.h" ) - @unittest.skipIf( - os.environ.get("BZLMOD_ENABLED") == "0", - "whl_with_data1 is only available with bzlmod", - ) def test_whl_with_data2_included(self): module = self.assert_imported_from_venv("whl_with_data2") @@ -147,10 +139,6 @@ def test_whl_with_data2_included(self): self.include_dir_name / "whl_with_data2/header_file.h" ) - @unittest.skipIf( - os.environ.get("BZLMOD_ENABLED") == "0", - "whl_with_data is only available with bzlmod", - ) def test_whl_with_data_overlap(self): self.assert_venv_path_exists("data/overlap/both.txt") self.assert_venv_path_exists("data/overlap/data1.txt") From cdb2cf1ffcc5002587454fa62d8abd677e6e35d6 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 10:51:50 -0700 Subject: [PATCH 32/40] lint --- internal_dev_setup.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal_dev_setup.bzl b/internal_dev_setup.bzl index a72a014525..0bbcd97748 100644 --- a/internal_dev_setup.bzl +++ b/internal_dev_setup.bzl @@ -26,8 +26,8 @@ load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS") load("//python/private:pythons_hub.bzl", "hub_repo") # buildifier: disable=bzl-visibility load("//python/private:runtime_env_repo.bzl", "runtime_env_repo") # buildifier: disable=bzl-visibility load("//python/private/pypi:deps.bzl", "pypi_deps") # buildifier: disable=bzl-visibility -load("//python/private/pypi:whl_library.bzl", "whl_library") -load("//tests/support/whl_from_dir:whl_from_dir_repo.bzl", "whl_from_dir_repo") +load("//python/private/pypi:whl_library.bzl", "whl_library") # buildifier: disable=bzl-visibility +load("//tests/support/whl_from_dir:whl_from_dir_repo.bzl", "whl_from_dir_repo") # buildifier: disable=bzl-visibility def rules_python_internal_setup(): """Setup for development and testing of rules_python itself.""" From e7ca80dc72e6f9978bd2c8ffc5ff1f4f6790798b Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 10:52:40 -0700 Subject: [PATCH 33/40] tests: support whl_from_dir_repo on Windows The `whl_from_dir_repo` repository rule previously relied on the Unix `zip` utility to create wheels. Because this command isn't natively available on Windows, any tests that depended on repositories generated by this rule had to be explicitly skipped on Windows hosts. To fix this and expand our test coverage, this adds a native Windows fallback. When running on Windows, the rule now invokes a helper PowerShell script that uses .NET compression APIs to create the archive. This script ensures the resulting wheel remains uncompressed and uses zeroed-out timestamps to match the deterministic behavior of the original `zip -0X` command. With this constraint removed, the Unix-only compatibility flags (`SUPPORTS_BZLMOD_UNIXY`) have been dropped, enabling several namespace package and wheel-related integration tests to finally run on Windows. --- tests/implicit_namespace_packages/BUILD.bazel | 4 +- tests/pypi/whl_library/BUILD.bazel | 4 +- tests/support/support.bzl | 5 +- .../whl_from_dir/whl_from_dir_repo.bzl | 53 ++++++++++++++----- tests/support/whl_from_dir/zip.ps1 | 45 ++++++++++++++++ .../app_files_building_tests.bzl | 6 +-- tests/whl_with_build_files/BUILD.bazel | 4 +- 7 files changed, 94 insertions(+), 27 deletions(-) create mode 100644 tests/support/whl_from_dir/zip.ps1 diff --git a/tests/implicit_namespace_packages/BUILD.bazel b/tests/implicit_namespace_packages/BUILD.bazel index 42aca9b97f..b544c4d118 100644 --- a/tests/implicit_namespace_packages/BUILD.bazel +++ b/tests/implicit_namespace_packages/BUILD.bazel @@ -1,10 +1,10 @@ load("//python:py_test.bzl", "py_test") -load("//tests/support:support.bzl", "SUPPORTS_BZLMOD_UNIXY") +load("//tests/support:support.bzl", "SUPPORTS_BZLMOD") py_test( name = "namespace_packages_test", srcs = ["namespace_packages_test.py"], - target_compatible_with = SUPPORTS_BZLMOD_UNIXY, + target_compatible_with = SUPPORTS_BZLMOD, deps = [ "@implicit_namespace_ns_sub1//:pkg", "@implicit_namespace_ns_sub2//:pkg", diff --git a/tests/pypi/whl_library/BUILD.bazel b/tests/pypi/whl_library/BUILD.bazel index 599bb12a15..cade0d2b8e 100644 --- a/tests/pypi/whl_library/BUILD.bazel +++ b/tests/pypi/whl_library/BUILD.bazel @@ -1,10 +1,10 @@ load("//python:py_test.bzl", "py_test") -load("//tests/support:support.bzl", "SUPPORTS_BZLMOD_UNIXY") +load("//tests/support:support.bzl", "SUPPORTS_BZLMOD") py_test( name = "whl_library_extras_test", srcs = ["whl_library_extras_test.py"], - target_compatible_with = SUPPORTS_BZLMOD_UNIXY, + target_compatible_with = SUPPORTS_BZLMOD, deps = [ "@whl_library_extras_direct_dep//:pkg", ], diff --git a/tests/support/support.bzl b/tests/support/support.bzl index 9bd2c987b9..64f77d76bc 100644 --- a/tests/support/support.bzl +++ b/tests/support/support.bzl @@ -35,10 +35,7 @@ SUPPORTS_BOOTSTRAP_SCRIPT = select({ "//conditions:default": [], }) -SUPPORTS_BZLMOD_UNIXY = select({ - "@platforms//os:windows": ["@platforms//:incompatible"], - "//conditions:default": [], -}) if BZLMOD_ENABLED else ["@platforms//:incompatible"] +SUPPORTS_BZLMOD = [] if BZLMOD_ENABLED else ["@platforms//:incompatible"] NOT_WINDOWS = select({ "@platforms//os:windows": ["@platforms//:incompatible"], diff --git a/tests/support/whl_from_dir/whl_from_dir_repo.bzl b/tests/support/whl_from_dir/whl_from_dir_repo.bzl index 4e16e8ee4a..c827c8a0a0 100644 --- a/tests/support/whl_from_dir/whl_from_dir_repo.bzl +++ b/tests/support/whl_from_dir/whl_from_dir_repo.bzl @@ -11,20 +11,41 @@ def _whl_from_dir_repo(rctx): rctx.watch_tree(root) output = rctx.path(rctx.attr.output) - repo_utils.execute_checked( - rctx, - # cd to root so zip recursively takes everything there. - working_directory = str(root), - op = "WhlFromDir", - arguments = [ - "zip", - "-0", # Skip compressing - "-X", # Don't store file time or metadata - str(output), - "-r", - ".", - ], - ) + if repo_utils.get_platforms_os_name(rctx) == "windows": + powershell_exe = rctx.which("powershell.exe") or rctx.which("powershell") + if not powershell_exe: + fail("powershell not found on PATH") + + zip_script = rctx.path(rctx.attr._zip_script) + + repo_utils.execute_checked( + rctx, + op = "WhlFromDir", + arguments = [ + powershell_exe, + "-NoProfile", + "-File", + str(zip_script), + str(output), + str(root), + ], + # zip.ps1 handles relativizing paths. + ) + else: + repo_utils.execute_checked( + rctx, + # cd to root so zip recursively takes everything there. + working_directory = str(root), + op = "WhlFromDir", + arguments = [ + "zip", + "-0", # Skip compressing + "-X", # Don't store file time or metadata + str(output), + "-r", + ".", + ], + ) rctx.file("BUILD.bazel", 'exports_files(glob(["*"]))') whl_from_dir_repo = repository_rule( @@ -46,5 +67,9 @@ A file whose directory will be put into the output wheel. All files are included verbatim. """, ), + "_zip_script": attr.label( + default = "//tests/support/whl_from_dir:zip.ps1", + allow_single_file = True, + ), }, ) diff --git a/tests/support/whl_from_dir/zip.ps1 b/tests/support/whl_from_dir/zip.ps1 new file mode 100644 index 0000000000..1e8c199cde --- /dev/null +++ b/tests/support/whl_from_dir/zip.ps1 @@ -0,0 +1,45 @@ +param ( + [Parameter(Position=0, Mandatory=$true)] + [string]$Output, + + [Parameter(Position=1, Mandatory=$true)] + [string]$Root +) + +Add-Type -AssemblyName System.IO.Compression + +$fixedTime = [datetime]"1980-01-01T00:00:00" +$RootFull = (Resolve-Path $Root).Path + +$stream = [System.IO.File]::Open($Output, [System.IO.FileMode]::Create) +try { + $archive = [System.IO.Compression.ZipArchive]::new($stream, [System.IO.Compression.ZipArchiveMode]::Create) + try { + $files = Get-ChildItem -Path $RootFull -Recurse -File + foreach ($file in $files) { + # Relativize path and normalize separators + $relPath = $file.FullName.Substring($RootFull.Length).TrimStart('\', '/') + $relPath = $relPath -replace '\\', '/' + + $entry = $archive.CreateEntry($relPath, [System.IO.Compression.CompressionLevel]::NoCompression) + $entry.LastWriteTime = $fixedTime + + $entryStream = $entry.Open() + try { + $fileStream = [System.IO.File]::OpenRead($file.FullName) + try { + $fileStream.CopyTo($entryStream) + } finally { + $fileStream.Dispose() + } + } finally { + $entryStream.Dispose() + } + } + } finally { + $archive.Dispose() + } +} finally { + $stream.Dispose() +} + diff --git a/tests/venv_site_packages_libs/app_files_building/app_files_building_tests.bzl b/tests/venv_site_packages_libs/app_files_building/app_files_building_tests.bzl index d808eae7e9..66ba7076a9 100644 --- a/tests/venv_site_packages_libs/app_files_building/app_files_building_tests.bzl +++ b/tests/venv_site_packages_libs/app_files_building/app_files_building_tests.bzl @@ -7,7 +7,7 @@ load("//python:py_library.bzl", "py_library") load("//python/private:common_labels.bzl", "labels") # buildifier: disable=bzl-visibility load("//python/private:py_info.bzl", "VenvSymlinkEntry", "VenvSymlinkKind") # buildifier: disable=bzl-visibility load("//python/private:venv_runfiles.bzl", "build_link_map", "get_venv_symlinks") # buildifier: disable=bzl-visibility -load("//tests/support:support.bzl", "SUPPORTS_BZLMOD_UNIXY") +load("//tests/support:support.bzl", "SUPPORTS_BZLMOD") def _empty_files_impl(ctx): files = [] @@ -425,7 +425,7 @@ def _test_optimized_grouping_pkgutil_whls(name): "@pkgutil_nspkg1//:pkg", "@pkgutil_nspkg2//:pkg", ], - target_compatible_with = SUPPORTS_BZLMOD_UNIXY, + target_compatible_with = SUPPORTS_BZLMOD, ) analysis_test( name = name, @@ -435,7 +435,7 @@ def _test_optimized_grouping_pkgutil_whls(name): labels.VENVS_SITE_PACKAGES: "yes", }, attr_values = dict( - target_compatible_with = SUPPORTS_BZLMOD_UNIXY, + target_compatible_with = SUPPORTS_BZLMOD, ), ) diff --git a/tests/whl_with_build_files/BUILD.bazel b/tests/whl_with_build_files/BUILD.bazel index e26dc1c3a6..1202876485 100644 --- a/tests/whl_with_build_files/BUILD.bazel +++ b/tests/whl_with_build_files/BUILD.bazel @@ -1,9 +1,9 @@ load("//python:py_test.bzl", "py_test") -load("//tests/support:support.bzl", "SUPPORTS_BZLMOD_UNIXY") +load("//tests/support:support.bzl", "SUPPORTS_BZLMOD") py_test( name = "verify_files_test", srcs = ["verify_files_test.py"], - target_compatible_with = SUPPORTS_BZLMOD_UNIXY, + target_compatible_with = SUPPORTS_BZLMOD, deps = ["@somepkg_with_build_files//:pkg"], ) From e35d1a40507bd1b7d0d476bc42481e18349b7a3a Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 12:53:55 -0700 Subject: [PATCH 34/40] move data scheme to venv root --- examples/pip_parse/pip_parse_test.py | 10 +++---- python/private/py_executable.bzl | 4 ++- python/private/venv_runfiles.bzl | 26 ++++++++++++++++--- .../data/bin/data_overlap.sh | 1 + .../data/include/data_overlap.h | 1 + .../data/site-packages/data_overlap.py | 1 + .../headers/data_overlap.h | 1 + .../purelib/data_overlap.py | 1 + .../scripts/data_overlap.sh | 1 + .../whl_with_data1-1.0.dist-info/RECORD | 6 +++++ tests/venv_site_packages_libs/bin.py | 14 +++++----- 11 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/bin/data_overlap.sh create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/include/data_overlap.h create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/site-packages/data_overlap.py create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/data_overlap.h create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/data_overlap.py create mode 100644 tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/data_overlap.sh diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index c532dff564..961038d3db 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -54,11 +54,11 @@ def test_data(self): expected = [ "bin/s3cmd", - "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", + "share/doc/packages/s3cmd/INSTALL.md", + "share/doc/packages/s3cmd/LICENSE", + "share/doc/packages/s3cmd/NEWS", + "share/doc/packages/s3cmd/README.md", + "share/man/man1/s3cmd.1", ] self.assertListEqual(actual, expected) diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index ab09926faa..6197c0c789 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -575,11 +575,13 @@ def _create_venv(ctx, output_prefix, imports, runtime_details, add_runfiles_root computed_substitutions = computed_subs, ) + # See https://docs.python.org/3/library/sysconfig.html#posix-prefix + # for how schemes map under the venv. venv_dir_map = { VenvSymlinkKind.BIN: "{}/{}".format(venv_ctx_rel_root, venv_details.bin_dir), VenvSymlinkKind.LIB: site_packages, VenvSymlinkKind.INCLUDE: "{}/{}".format(venv_ctx_rel_root, venv_details.include_dir), - VenvSymlinkKind.DATA: "{}/data".format(venv_ctx_rel_root), + VenvSymlinkKind.DATA: venv_ctx_rel_root, } venv_app_files = create_venv_app_files( ctx, diff --git a/python/private/venv_runfiles.bzl b/python/private/venv_runfiles.bzl index 1c518bccc3..cfcc753866 100644 --- a/python/private/venv_runfiles.bzl +++ b/python/private/venv_runfiles.bzl @@ -69,10 +69,16 @@ def create_venv_app_files(ctx, deps, venv_dir_map): ctx.label.package, ) + seen_bin_venv_paths = {} + for kind, kind_map in link_map.items(): base = venv_dir_map[kind] for venv_path, link_to in kind_map.items(): bin_venv_path = paths.join(base, venv_path) + if bin_venv_path in seen_bin_venv_paths: + continue + seen_bin_venv_paths[bin_venv_path] = True + if is_file(link_to): # use paths.join to handle ctx.label.package = "" # runfile_prefix should be prepended as we use runfiles.root_symlinks @@ -418,9 +424,23 @@ def get_venv_symlinks( if not cannot_be_linked_directly.get(dirname, False): cannot_be_linked_directly[dirname] = True - # bin, include, and data are also shared across wheels, so we cannot link - # them directly if they are at the top level. - for dirname in ["bin", "include", "data"]: + for dirname in [ + # The venv directories that bin, include, and data get put into are + # shared across wheels, are also shared across wheels, so we cannot link + # them directly + "bin", + "include", + "data", + # The data scheme is overlaid on the venv root, so the files under it + # could, in theory, get installed into e.g. bin/ or similar. Explicitly + # mark them as non-directly linkable to avoid issues. + "data/bin", + "data/include", + "data/lib", + "data/Scripts", + "data/Include", + "data/Lib", + ]: cannot_be_linked_directly[dirname] = True # At this point, venv_symlinks has entries for the shared libraries diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/bin/data_overlap.sh b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/bin/data_overlap.sh new file mode 100644 index 0000000000..b47ce4e9f3 --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/bin/data_overlap.sh @@ -0,0 +1 @@ +echo data_bin diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/include/data_overlap.h b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/include/data_overlap.h new file mode 100644 index 0000000000..299c39d0a7 --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/include/data_overlap.h @@ -0,0 +1 @@ +/* data_include */ diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/site-packages/data_overlap.py b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/site-packages/data_overlap.py new file mode 100644 index 0000000000..d3ee4d8a3f --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/data/site-packages/data_overlap.py @@ -0,0 +1 @@ +# data_site_packages diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/data_overlap.h b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/data_overlap.h new file mode 100644 index 0000000000..ffd49d0cee --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/headers/data_overlap.h @@ -0,0 +1 @@ +/* headers */ diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/data_overlap.py b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/data_overlap.py new file mode 100644 index 0000000000..f82e46670f --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/purelib/data_overlap.py @@ -0,0 +1 @@ +# purelib diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/data_overlap.sh b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/data_overlap.sh new file mode 100644 index 0000000000..d6eb28dc3d --- /dev/null +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.data/scripts/data_overlap.sh @@ -0,0 +1 @@ +echo scripts diff --git a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD index d0eead551d..a39e9ed7ad 100644 --- a/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD +++ b/tests/repos/whl_with_data1/whl_with_data1-1.0.dist-info/RECORD @@ -10,3 +10,9 @@ whl_with_data1-1.0.data/scripts/overlap/both.sh,sha256=123,123 whl_with_data1-1.0.data/scripts/overlap/script1.sh,sha256=123,123 whl_with_data1-1.0.data/headers/overlap/both.h,sha256=123,123 whl_with_data1-1.0.data/headers/overlap/header1.h,sha256=123,123 +whl_with_data1-1.0.data/scripts/data_overlap.sh,sha256=123,123 +whl_with_data1-1.0.data/data/bin/data_overlap.sh,sha256=123,123 +whl_with_data1-1.0.data/headers/data_overlap.h,sha256=123,123 +whl_with_data1-1.0.data/data/include/data_overlap.h,sha256=123,123 +whl_with_data1-1.0.data/purelib/data_overlap.py,sha256=123,123 +whl_with_data1-1.0.data/data/site-packages/data_overlap.py,sha256=123,123 diff --git a/tests/venv_site_packages_libs/bin.py b/tests/venv_site_packages_libs/bin.py index 1abe90d157..368251e75b 100644 --- a/tests/venv_site_packages_libs/bin.py +++ b/tests/venv_site_packages_libs/bin.py @@ -113,7 +113,7 @@ def test_whl_with_data1_included(self): venv_root = self.venv # data - self.assert_venv_path_exists("data/whl_with_data1/data_data_file.txt") + self.assert_venv_path_exists("whl_with_data1/data_data_file.txt") # scripts self.assert_venv_path_exists(self.bin_dir_name / "whl_script.sh") @@ -131,18 +131,18 @@ def test_whl_with_data2_included(self): self.assert_venv_path_exists(self.bin_dir_name / "whl_script.sh") - # Ensure that `data` files are unpacked in `venv/data/` - # and then linked as `venv/data/whl_with_data1/data_data_file.txt`. - self.assert_venv_path_exists("data/whl_with_data2/data_data_file.txt") + # Ensure that `data` files are unpacked in `venv/root/` + # and then linked as `venv/whl_with_data1/data_data_file.txt`. + self.assert_venv_path_exists("whl_with_data2/data_data_file.txt") self.assert_venv_path_exists( self.include_dir_name / "whl_with_data2/header_file.h" ) def test_whl_with_data_overlap(self): - self.assert_venv_path_exists("data/overlap/both.txt") - self.assert_venv_path_exists("data/overlap/data1.txt") - self.assert_venv_path_exists("data/overlap/data2.txt") + self.assert_venv_path_exists("overlap/both.txt") + self.assert_venv_path_exists("overlap/data1.txt") + self.assert_venv_path_exists("overlap/data2.txt") self.assert_venv_path_exists(self.bin_dir_name / "overlap/both.sh") self.assert_venv_path_exists(self.bin_dir_name / "overlap/script1.sh") From e38fd1c2426741aaf95163a6ec492188b044960e Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 12:56:43 -0700 Subject: [PATCH 35/40] move cannot_be_linked_directly init earlier --- python/private/venv_runfiles.bzl | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/python/private/venv_runfiles.bzl b/python/private/venv_runfiles.bzl index cfcc753866..bff389ff96 100644 --- a/python/private/venv_runfiles.bzl +++ b/python/private/venv_runfiles.bzl @@ -336,6 +336,26 @@ def get_venv_symlinks( all_files = sorted(files, key = lambda f: f.short_path) + cannot_be_linked_directly = {} + for dirname in [ + # The venv directories that bin, include, and data get put into are + # shared across wheels, are also shared across wheels, so we cannot link + # them directly + "bin", + "include", + "data", + # The data scheme is overlaid on the venv root, so the files under it + # could, in theory, get installed into e.g. bin/ or similar. Explicitly + # mark them as non-directly linkable to avoid issues. + "data/bin", + "data/include", + "data/lib", + "data/Scripts", + "data/Include", + "data/Lib", + ]: + cannot_be_linked_directly[dirname] = True + # dict[str venv-relative dirname, bool is_namespace_package] namespace_package_dirs = { ns: True @@ -343,10 +363,10 @@ def get_venv_symlinks( } # venv paths that cannot be directly linked. Dict acting as set. - cannot_be_linked_directly = { + cannot_be_linked_directly.update({ dirname: True for dirname in namespace_package_dirs.keys() - } + }) for f in namespace_package_files: venv_path, _ = _get_file_venv_path(ctx, f, site_packages_root) if venv_path == None: @@ -424,25 +444,6 @@ def get_venv_symlinks( if not cannot_be_linked_directly.get(dirname, False): cannot_be_linked_directly[dirname] = True - for dirname in [ - # The venv directories that bin, include, and data get put into are - # shared across wheels, are also shared across wheels, so we cannot link - # them directly - "bin", - "include", - "data", - # The data scheme is overlaid on the venv root, so the files under it - # could, in theory, get installed into e.g. bin/ or similar. Explicitly - # mark them as non-directly linkable to avoid issues. - "data/bin", - "data/include", - "data/lib", - "data/Scripts", - "data/Include", - "data/Lib", - ]: - cannot_be_linked_directly[dirname] = True - # At this point, venv_symlinks has entries for the shared libraries # and cannot_be_linked_directly has the directories that cannot be # directly linked. Next, we loop over the remaining files and group From 9184bcc623cacb6561853bd6228873c1f27f56d4 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 13:04:16 -0700 Subject: [PATCH 36/40] re-add data prefix to pip_parse test. It is verifying the whl_library extract --- examples/pip_parse/pip_parse_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/pip_parse/pip_parse_test.py b/examples/pip_parse/pip_parse_test.py index 961038d3db..c532dff564 100644 --- a/examples/pip_parse/pip_parse_test.py +++ b/examples/pip_parse/pip_parse_test.py @@ -54,11 +54,11 @@ def test_data(self): expected = [ "bin/s3cmd", - "share/doc/packages/s3cmd/INSTALL.md", - "share/doc/packages/s3cmd/LICENSE", - "share/doc/packages/s3cmd/NEWS", - "share/doc/packages/s3cmd/README.md", - "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", ] self.assertListEqual(actual, expected) From 51f614bd809f6c12977fb6242e68b501a3b9f939 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 13:56:41 -0700 Subject: [PATCH 37/40] handle when directly linking to a file on windows --- python/private/venv_runfiles.bzl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/private/venv_runfiles.bzl b/python/private/venv_runfiles.bzl index bff389ff96..bbf3d8b85d 100644 --- a/python/private/venv_runfiles.bzl +++ b/python/private/venv_runfiles.bzl @@ -86,6 +86,18 @@ def create_venv_app_files(ctx, deps, venv_dir_map): symlink_from = paths.join(runfile_prefix, ctx.label.package, bin_venv_path) runfiles_symlinks[symlink_from] = link_to + + # On Windows, we need to explicitly create the symlink in the venv + # because the bootstrap script won't otherwise know about it. + if is_windows: + rf_path = paths.join(ctx_rf_path, bin_venv_path) + _, _, venv_path = bin_venv_path.partition(".venv/") + explicit_symlinks.append(ExplicitSymlink( + runfiles_path = rf_path, + venv_path = venv_path, + link_to_path = runfiles_root_path(ctx, link_to.short_path), + files = depset([link_to]), + )) elif not is_windows: venv_link = ctx.actions.declare_symlink(bin_venv_path) venv_link_rf_path = runfiles_root_path(ctx, venv_link.short_path) From 9681318076dc1b1ca831cd49c439a174a027975a Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 14:55:47 -0700 Subject: [PATCH 38/40] always incldue data label --- python/private/pypi/whl_library_targets.bzl | 9 +++------ python/private/venv_runfiles.bzl | 3 +-- .../whl_library_targets/whl_library_targets_tests.bzl | 6 +++--- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index c511d3000f..f77366a37f 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -381,12 +381,9 @@ def whl_library_targets( namespace_package_files += generated_namespace_package_files srcs = srcs + generated_namespace_package_files - # This must be doe after the above because create_inits() is macro-phase, - # so can't handle select() values. - data = data + select({ - _IS_VENV_SITE_PACKAGES_YES: [DATA_LABEL], - "//conditions:default": [], - }) + # This is done after create_inits() is called so that the data scheme + # files don't have such files created in their directories. + data = data + [DATA_LABEL] rules.py_library( name = py_library_label, diff --git a/python/private/venv_runfiles.bzl b/python/private/venv_runfiles.bzl index bbf3d8b85d..a94f29f71c 100644 --- a/python/private/venv_runfiles.bzl +++ b/python/private/venv_runfiles.bzl @@ -351,8 +351,7 @@ def get_venv_symlinks( cannot_be_linked_directly = {} for dirname in [ # The venv directories that bin, include, and data get put into are - # shared across wheels, are also shared across wheels, so we cannot link - # them directly + # shared across wheels, so we cannot link them directly "bin", "include", "data", diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl index 659366ff05..763dcbccbb 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -249,7 +249,7 @@ def _test_whl_and_library_deps_from_requires(env): "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt", "data"], "imports": ["site-packages"], "deps": ["@pypi//bar:pkg"] + select({ ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], @@ -365,7 +365,7 @@ def _test_whl_and_library_deps(env): "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/PYI.pyi"], - "data": ["site-packages/foo/DATA.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/DATA.txt", "data"], "imports": ["site-packages"], "deps": [ "@pypi_bar_baz//:pkg", @@ -448,7 +448,7 @@ def _test_group(env): "//conditions:default": ["_create_inits_target"], }), "pyi_srcs": ["site-packages/foo/pyi.pyi"], - "data": ["site-packages/foo/data.txt"] + select({Label("//python/config_settings:_is_venvs_site_packages_yes"): ["data"], "//conditions:default": []}), + "data": ["site-packages/foo/data.txt", "data"], "imports": ["site-packages"], "deps": ["@pypi_bar_baz//:pkg"] + select({ "@platforms//os:linux": ["@pypi_box//:pkg"], From 50cc8f0ca80c7276cb428fd2f01102d5e105fb16 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 15:13:42 -0700 Subject: [PATCH 39/40] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 225a1c1c00..7c19d1176e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,8 @@ END_UNRELEASED_TEMPLATE ### Changed * (gazelle) WORKSPACE's bazel-gazelle dependency bumped from 0.36.0 to 0.47.0. The go version was also bumped from 1.21.13 to 1.22.9. +* (pypi) The data files of a wheel (bin, includes, etc) are now always included + as a library's data dependencies. {#v0-0-0-fixed} ### Fixed @@ -74,6 +76,8 @@ END_UNRELEASED_TEMPLATE adding `config_setting` labels to all registered toolchains. * (windows) Full venv support for Windows is available. Set {obj}`--venvs_site_packages=yes` to enable. +* (test/binaries) When {obj}`--venv_site_packages=yes` is enabled, + wheel `data`, `bin`, and `include` files are populated into the venv. * (runfiles) Added a pathlib-compatible API: {obj}`Runfiles.root()` Fixes [#3296](https://github.com/bazel-contrib/rules_python/issues/3296). * (toolchains) `3.13.12`, `3.14.3` Python toolchain from [20260325] release. From cd18acc788f406a46496dcb3945439a2fb2e11c9 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 26 Apr 2026 15:20:22 -0700 Subject: [PATCH 40/40] cleanup --- tests/venv_site_packages_libs/BUILD.bazel | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index bc187b435a..c99426b375 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -1,4 +1,3 @@ -load("@rules_python//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility load("@rules_shell//shell:sh_test.bzl", "sh_test") load("//python:py_library.bzl", "py_library") load("//tests/support:py_reconfig.bzl", "py_reconfig_test") @@ -33,9 +32,6 @@ py_reconfig_test( name = "venvs_site_packages_libs_test", srcs = ["bin.py"], bootstrap_impl = "script", - env = { - "BZLMOD_ENABLED": "1" if BZLMOD_ENABLED else "0", - }, main = "bin.py", venvs_site_packages = "yes", deps = [ @@ -49,7 +45,6 @@ py_reconfig_test( "@other//nspkg_gamma", "@other//nspkg_single", "@other//with_external_data", - ] + [ "@whl_with_data1//:pkg", "@whl_with_data2//:pkg", ],