diff --git a/CHANGELOG.md b/CHANGELOG.md index dc45d2e95e..70f30ac67b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,10 @@ END_UNRELEASED_TEMPLATE * (uv) use the astral.sh mirror as the preferred url for binary downloads, with github.com as a fallback; for uv >= 0.11.0, read the checksums directly from the dist-manifest contents. +* (pypi) Fix `importlib.metadata.files` by ensuring `RECORD` is included in + installed wheel targets, except when built from sdist + ([#3024](https://github.com/bazel-contrib/rules_python/issues/3024)). + {#v0-0-0-added} ### Added diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index b3a52cd18c..01a89aadcc 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -374,11 +374,9 @@ def whl_library_targets( "**/*.py", "**/*.pyc", "**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNNN are created - # RECORD is known to contain sha256 checksums of files which might include the checksums - # of generated files produced when wheels are installed. The file is ignored to avoid - # Bazel caching issues. - "**/*.dist-info/RECORD", ] + if sdist_filename: + _data_exclude.append("**/*.dist-info/RECORD") for item in data_exclude: if item not in _data_exclude: _data_exclude.append(item) 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 ec28bfbb39..91db15f296 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -272,7 +272,6 @@ def _test_whl_and_library_deps_from_requires(env): "**/*.py", "**/*.pyc", "**/*.pyc.*", - "**/*.dist-info/RECORD", ], allow_empty = True, ), @@ -471,13 +470,53 @@ def _test_group(env): "**/*.py", "**/*.pyc", "**/*.pyc.*", - "**/*.dist-info/RECORD", ], allow_empty = True), mocks.glob_call(["site-packages/**/*.pyi"], allow_empty = True), ]) _tests.append(_test_group) +def _test_sdist_excludes_record(env): + py_library_calls = [] + m_glob = mocks.glob() + m_glob.results.append([]) # bin + m_glob.results.append([]) # rewrite-bin + m_glob.results.append([]) # srcs + m_glob.results.append([]) # data + m_glob.results.append([]) # pyi + + whl_library_targets( + name = "foo.whl", + dep_template = "@pypi_{name}//:{target}", + sdist_filename = "foo.tar.gz", + filegroups = {}, + native = struct( + filegroup = lambda **_: None, + config_setting = lambda **_: None, + glob = m_glob.glob, + ), + rules = struct( + py_library = lambda **kwargs: py_library_calls.append(kwargs), + create_inits = lambda **kwargs: [], + venv_rewrite_shebang = lambda **kwargs: None, + ), + ) + + env.expect.that_collection(m_glob.calls).contains_at_least([ + mocks.glob_call( + ["site-packages/**/*"], + exclude = [ + "**/*.py", + "**/*.pyc", + "**/*.pyc.*", + "**/*.dist-info/RECORD", + ], + allow_empty = True, + ), + ]) + +_tests.append(_test_sdist_excludes_record) + def whl_library_targets_test_suite(name): """create the test suite. diff --git a/tests/venv_site_packages_libs/BUILD.bazel b/tests/venv_site_packages_libs/BUILD.bazel index d44bbcbb63..6a7b3b9e12 100644 --- a/tests/venv_site_packages_libs/BUILD.bazel +++ b/tests/venv_site_packages_libs/BUILD.bazel @@ -85,3 +85,17 @@ py_reconfig_test( "@whl_with_data2//:pkg", ], ) + +py_reconfig_test( + name = "importlib_metadata_test", + srcs = ["importlib_metadata_test.py"], + bootstrap_impl = select({ + "@platforms//os:windows": "system_python", + "//conditions:default": "script", + }), + main = "importlib_metadata_test.py", + venvs_site_packages = "yes", + deps = [ + "@whl_with_data1//:pkg", + ], +) 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 66ba7076a9..65124076c6 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 @@ -471,6 +471,7 @@ def _test_optimized_grouping_pkgutil_whls_impl(env, target): files = [ "../+internal_dev_deps+pkgutil_nspkg1/site-packages/pkgutil_nspkg1-1.0.dist-info/INSTALLER", "../+internal_dev_deps+pkgutil_nspkg1/site-packages/pkgutil_nspkg1-1.0.dist-info/METADATA", + "../+internal_dev_deps+pkgutil_nspkg1/site-packages/pkgutil_nspkg1-1.0.dist-info/RECORD", "../+internal_dev_deps+pkgutil_nspkg1/site-packages/pkgutil_nspkg1-1.0.dist-info/WHEEL", ], ), @@ -495,6 +496,7 @@ def _test_optimized_grouping_pkgutil_whls_impl(env, target): files = [ "../+internal_dev_deps+pkgutil_nspkg2/site-packages/pkgutil_nspkg2-1.0.dist-info/INSTALLER", "../+internal_dev_deps+pkgutil_nspkg2/site-packages/pkgutil_nspkg2-1.0.dist-info/METADATA", + "../+internal_dev_deps+pkgutil_nspkg2/site-packages/pkgutil_nspkg2-1.0.dist-info/RECORD", "../+internal_dev_deps+pkgutil_nspkg2/site-packages/pkgutil_nspkg2-1.0.dist-info/WHEEL", ], ), diff --git a/tests/venv_site_packages_libs/importlib_metadata_test.py b/tests/venv_site_packages_libs/importlib_metadata_test.py new file mode 100644 index 0000000000..178ff14c50 --- /dev/null +++ b/tests/venv_site_packages_libs/importlib_metadata_test.py @@ -0,0 +1,24 @@ +import importlib.metadata +import unittest + + +class ImportlibMetadataTest(unittest.TestCase): + + def test_importlib_metadata_files(self): + files = importlib.metadata.files("whl-with-data1") + self.assertIsNotNone(files, "importlib.metadata.files returned None") + self.assertGreater( + len(files), 0, "importlib.metadata.files returned empty list" + ) + + # Verify it contains some expected files. + # The RECORD file lists paths relative to the installation root (site-packages). + # whl_with_data1-1.0.data/purelib/data_overlap.py should be installed as data_overlap.py + # whl_with_data1-1.0.data/platlib/whl_with_data1/platlib_file.txt should be whl_with_data1/platlib_file.txt + + file_names = [f.name for f in files] + self.assertIn("data_overlap.py", file_names) + + +if __name__ == "__main__": + unittest.main()