diff --git a/.bazelrc b/.bazelrc index 8997db9f91..d7e1771336 100644 --- a/.bazelrc +++ b/.bazelrc @@ -4,8 +4,8 @@ # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it) # To update these lines, execute # `bazel run @rules_bazel_integration_test//tools:update_deleted_packages` -build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data,tests/whl_with_build_files/testdata,tests/whl_with_build_files/testdata/somepkg,tests/whl_with_build_files/testdata/somepkg-1.0.dist-info,tests/whl_with_build_files/testdata/somepkg/subpkg -query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data,tests/whl_with_build_files/testdata,tests/whl_with_build_files/testdata/somepkg,tests/whl_with_build_files/testdata/somepkg-1.0.dist-info,tests/whl_with_build_files/testdata/somepkg/subpkg +build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,rules_python-repro,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data,tests/whl_with_build_files/testdata,tests/whl_with_build_files/testdata/somepkg,tests/whl_with_build_files/testdata/somepkg-1.0.dist-info,tests/whl_with_build_files/testdata/somepkg/subpkg +query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,rules_python-repro,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data,tests/whl_with_build_files/testdata,tests/whl_with_build_files/testdata/somepkg,tests/whl_with_build_files/testdata/somepkg-1.0.dist-info,tests/whl_with_build_files/testdata/somepkg/subpkg test --test_output=errors diff --git a/MODULE.bazel b/MODULE.bazel index b1d8711815..39dda3f8c5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -102,6 +102,8 @@ internal_dev_deps = use_extension( use_repo( internal_dev_deps, "buildkite_config", + "implicit_namespace_ns_sub1", + "implicit_namespace_ns_sub2", "rules_python_runtime_env_tc_info", "somepkg_with_build_files", "whl_with_build_files", diff --git a/python/private/internal_dev_deps.bzl b/python/private/internal_dev_deps.bzl index bb7d76f56a..ca34dc698a 100644 --- a/python/private/internal_dev_deps.bzl +++ b/python/private/internal_dev_deps.bzl @@ -30,6 +30,7 @@ def _internal_dev_deps_impl(mctx): ) runtime_env_repo(name = "rules_python_runtime_env_tc_info") + # Setup for //tests/whl_with_build_files whl_from_dir_repo( name = "whl_with_build_files", root = "//tests/whl_with_build_files:testdata/BUILD.bazel", @@ -41,6 +42,31 @@ def _internal_dev_deps_impl(mctx): requirement = "somepkg", ) + # Setup for //tests/implicit_namespace_packages + whl_from_dir_repo( + name = "implicit_namespace_ns_sub1_whl", + root = "//tests/implicit_namespace_packages:testdata/ns-sub1/BUILD.bazel", + output = "ns_sub1-1.0-any-none-any.whl", + ) + whl_library( + name = "implicit_namespace_ns_sub1", + whl_file = "@implicit_namespace_ns_sub1_whl//:ns_sub1-1.0-any-none-any.whl", + requirement = "ns-sub1", + enable_implicit_namespace_pkgs = False, + ) + + whl_from_dir_repo( + name = "implicit_namespace_ns_sub2_whl", + root = "//tests/implicit_namespace_packages:testdata/ns-sub2/BUILD.bazel", + output = "ns_sub2-1.0-any-none-any.whl", + ) + whl_library( + name = "implicit_namespace_ns_sub2", + whl_file = "@implicit_namespace_ns_sub2_whl//:ns_sub2-1.0-any-none-any.whl", + requirement = "ns-sub2", + enable_implicit_namespace_pkgs = False, + ) + internal_dev_deps = module_extension( implementation = _internal_dev_deps_impl, doc = "This extension creates internal rules_python dev dependencies.", diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index 474f39a34d..95c1f5e981 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -30,7 +30,7 @@ load( "WHEEL_FILE_IMPL_LABEL", "WHEEL_FILE_PUBLIC_LABEL", ) -load(":namespace_pkgs.bzl", "create_inits") +load(":namespace_pkgs.bzl", _create_inits = "create_inits") load(":pep508_deps.bzl", "deps") def whl_library_targets_from_requires( @@ -120,6 +120,7 @@ def whl_library_targets( py_binary = py_binary, py_library = py_library, env_marker_setting = env_marker_setting, + create_inits = _create_inits, )): """Create all of the whl_library targets. @@ -334,7 +335,7 @@ def whl_library_targets( if not enable_implicit_namespace_pkgs: srcs = srcs + getattr(native, "select", select)({ Label("//python/config_settings:is_venvs_site_packages"): [], - "//conditions:default": create_inits( + "//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. root = "site-packages", diff --git a/tests/implicit_namespace_packages/BUILD.bazel b/tests/implicit_namespace_packages/BUILD.bazel new file mode 100644 index 0000000000..42aca9b97f --- /dev/null +++ b/tests/implicit_namespace_packages/BUILD.bazel @@ -0,0 +1,12 @@ +load("//python:py_test.bzl", "py_test") +load("//tests/support:support.bzl", "SUPPORTS_BZLMOD_UNIXY") + +py_test( + name = "namespace_packages_test", + srcs = ["namespace_packages_test.py"], + target_compatible_with = SUPPORTS_BZLMOD_UNIXY, + deps = [ + "@implicit_namespace_ns_sub1//:pkg", + "@implicit_namespace_ns_sub2//:pkg", + ], +) diff --git a/tests/implicit_namespace_packages/namespace_packages_test.py b/tests/implicit_namespace_packages/namespace_packages_test.py new file mode 100644 index 0000000000..ea47c08fd2 --- /dev/null +++ b/tests/implicit_namespace_packages/namespace_packages_test.py @@ -0,0 +1,24 @@ +import unittest + + +class NamespacePackagesTest(unittest.TestCase): + + def test_both_importable(self): + import nspkg + import nspkg.subpkg1 + import nspkg.subpkg1.subpkgmod + import nspkg.subpkg2.subpkgmod + + self.assertEqual("nspkg.subpkg1", nspkg.subpkg1.expected_name) + self.assertEqual( + "nspkg.subpkg1.subpkgmod", nspkg.subpkg1.subpkgmod.expected_name + ) + + self.assertEqual("nspkg.subpkg2", nspkg.subpkg2.expected_name) + self.assertEqual( + "nspkg.subpkg2.subpkgmod", nspkg.subpkg2.subpkgmod.expected_name + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/METADATA b/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/METADATA new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/RECORD b/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/RECORD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/WHEEL b/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/WHEEL new file mode 100644 index 0000000000..a64521a1cc --- /dev/null +++ b/tests/implicit_namespace_packages/testdata/ns-sub1/ns-sub1-1.0.dist-info/WHEEL @@ -0,0 +1 @@ +Wheel-Version: 1.0 diff --git a/tests/implicit_namespace_packages/testdata/ns-sub1/nspkg/subpkg1/__init__.py b/tests/implicit_namespace_packages/testdata/ns-sub1/nspkg/subpkg1/__init__.py new file mode 100644 index 0000000000..6657257dc6 --- /dev/null +++ b/tests/implicit_namespace_packages/testdata/ns-sub1/nspkg/subpkg1/__init__.py @@ -0,0 +1 @@ +expected_name = "nspkg.subpkg1" diff --git a/tests/implicit_namespace_packages/testdata/ns-sub1/nspkg/subpkg1/subpkgmod.py b/tests/implicit_namespace_packages/testdata/ns-sub1/nspkg/subpkg1/subpkgmod.py new file mode 100644 index 0000000000..b03bf39642 --- /dev/null +++ b/tests/implicit_namespace_packages/testdata/ns-sub1/nspkg/subpkg1/subpkgmod.py @@ -0,0 +1 @@ +expected_name = "nspkg.subpkg1.subpkgmod" diff --git a/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/METADATA b/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/METADATA new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/RECORD b/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/RECORD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/WHEEL b/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/WHEEL new file mode 100644 index 0000000000..a64521a1cc --- /dev/null +++ b/tests/implicit_namespace_packages/testdata/ns-sub2/ns_sub2-1.0.dist-info/WHEEL @@ -0,0 +1 @@ +Wheel-Version: 1.0 diff --git a/tests/implicit_namespace_packages/testdata/ns-sub2/nspkg/subpkg2/__init__.py b/tests/implicit_namespace_packages/testdata/ns-sub2/nspkg/subpkg2/__init__.py new file mode 100644 index 0000000000..29bfb67066 --- /dev/null +++ b/tests/implicit_namespace_packages/testdata/ns-sub2/nspkg/subpkg2/__init__.py @@ -0,0 +1 @@ +expected_name = "nspkg.subpkg2" diff --git a/tests/implicit_namespace_packages/testdata/ns-sub2/nspkg/subpkg2/subpkgmod.py b/tests/implicit_namespace_packages/testdata/ns-sub2/nspkg/subpkg2/subpkgmod.py new file mode 100644 index 0000000000..45a28eb851 --- /dev/null +++ b/tests/implicit_namespace_packages/testdata/ns-sub2/nspkg/subpkg2/subpkgmod.py @@ -0,0 +1 @@ +expected_name = "nspkg.subpkg2.subpkgmod" 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 22fe3ab7ca..bc58be9698 100644 --- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl +++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl @@ -16,18 +16,14 @@ load("@rules_testing//lib:test_suite.bzl", "test_suite") load("//python/private:glob_excludes.bzl", "glob_excludes") # buildifier: disable=bzl-visibility -load("//python/private/pypi:whl_library_targets.bzl", _whl_library_targets = "whl_library_targets", _whl_library_targets_from_requires = "whl_library_targets_from_requires") # buildifier: disable=bzl-visibility +load( + "//python/private/pypi:whl_library_targets.bzl", + "whl_library_targets", + "whl_library_targets_from_requires", +) # buildifier: disable=bzl-visibility _tests = [] -def whl_library_targets(**kwargs): - # Let's skip testing this for now - _whl_library_targets(enable_implicit_namespace_pkgs = True, **kwargs) - -def whl_library_targets_from_requires(**kwargs): - # Let's skip testing this for now - _whl_library_targets_from_requires(enable_implicit_namespace_pkgs = True, **kwargs) - def _test_filegroups(env): calls = [] @@ -190,6 +186,12 @@ def _test_whl_and_library_deps_from_requires(env): py_library_calls = [] env_marker_setting_calls = [] + mock_glob = _mock_glob() + + mock_glob.results.append(["site-packages/foo/SRCS.py"]) + mock_glob.results.append(["site-packages/foo/DATA.txt"]) + mock_glob.results.append(["site-packages/foo/PYI.pyi"]) + whl_library_targets_from_requires( name = "foo-0-py3-none-any.whl", metadata_name = "Foo", @@ -208,12 +210,13 @@ def _test_whl_and_library_deps_from_requires(env): native = struct( filegroup = lambda **kwargs: filegroup_calls.append(kwargs), config_setting = lambda **_: None, - glob = _glob, + glob = mock_glob.glob, select = _select, ), rules = struct( py_library = lambda **kwargs: py_library_calls.append(kwargs), env_marker_setting = lambda **kwargs: env_marker_setting_calls.append(kwargs), + create_inits = lambda *args, **kwargs: ["_create_inits_target"], ), ) @@ -228,34 +231,51 @@ def _test_whl_and_library_deps_from_requires(env): "visibility": ["//visibility:public"], }, ]) # buildifier: @unsorted-dict-items - env.expect.that_collection(py_library_calls).contains_exactly([ - { - "name": "pkg", - "srcs": _glob( - ["site-packages/**/*.py"], - exclude = [], - allow_empty = True, - ), - "pyi_srcs": _glob(["site-packages/**/*.pyi"], allow_empty = True), - "data": [] + _glob( - ["site-packages/**/*"], - exclude = [ - "**/*.py", - "**/*.pyc", - "**/*.pyc.*", - "**/*.dist-info/RECORD", - ] + glob_excludes.version_dependent_exclusions(), - ), - "imports": ["site-packages"], - "deps": ["@pypi//bar:pkg"] + _select({ - ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], - "//conditions:default": [], - }), - "tags": ["pypi_name=Foo", "pypi_version=0"], - "visibility": ["//visibility:public"], - "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), - }, - ]) # buildifier: @unsorted-dict-items + + env.expect.that_collection(py_library_calls).has_size(1) + if len(py_library_calls) != 1: + return + py_library_call = py_library_calls[0] + + 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"): [], + "//conditions:default": ["_create_inits_target"], + }), + "pyi_srcs": ["site-packages/foo/PYI.pyi"], + "data": ["site-packages/foo/DATA.txt"], + "imports": ["site-packages"], + "deps": ["@pypi//bar:pkg"] + _select({ + ":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"], + "//conditions:default": [], + }), + "tags": ["pypi_name=Foo", "pypi_version=0"], + "visibility": ["//visibility:public"], + "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), + }) # buildifier: @unsorted-dict-items + + env.expect.that_collection(mock_glob.calls).contains_exactly([ + # srcs call + _glob_call( + ["site-packages/**/*.py"], + exclude = [], + allow_empty = True, + ), + # data call + _glob_call( + ["site-packages/**/*"], + exclude = [ + "**/*.py", + "**/*.pyc", + "**/*.pyc.*", + "**/*.dist-info/RECORD", + ] + glob_excludes.version_dependent_exclusions(), + ), + # pyi call + _glob_call(["site-packages/**/*.pyi"], allow_empty = True), + ]) + env.expect.that_collection(env_marker_setting_calls).contains_exactly([ { "name": "include_bar_baz", @@ -269,6 +289,10 @@ _tests.append(_test_whl_and_library_deps_from_requires) def _test_whl_and_library_deps(env): filegroup_calls = [] py_library_calls = [] + mock_glob = _mock_glob() + mock_glob.results.append(["site-packages/foo/SRCS.py"]) + mock_glob.results.append(["site-packages/foo/DATA.txt"]) + mock_glob.results.append(["site-packages/foo/PYI.pyi"]) whl_library_targets( name = "foo.whl", @@ -290,11 +314,12 @@ def _test_whl_and_library_deps(env): native = struct( filegroup = lambda **kwargs: filegroup_calls.append(kwargs), config_setting = lambda **_: None, - glob = _glob, + glob = mock_glob.glob, select = _select, ), rules = struct( py_library = lambda **kwargs: py_library_calls.append(kwargs), + create_inits = lambda **kwargs: ["_create_inits_target"], ), ) @@ -320,45 +345,38 @@ def _test_whl_and_library_deps(env): "visibility": ["//visibility:public"], }, ]) # buildifier: @unsorted-dict-items - env.expect.that_collection(py_library_calls).contains_exactly([ - { - "name": "pkg", - "srcs": _glob( - ["site-packages/**/*.py"], - exclude = [], - allow_empty = True, - ), - "pyi_srcs": _glob(["site-packages/**/*.pyi"], allow_empty = True), - "data": [] + _glob( - ["site-packages/**/*"], - exclude = [ - "**/*.py", - "**/*.pyc", - "**/*.pyc.*", - "**/*.dist-info/RECORD", - ] + glob_excludes.version_dependent_exclusions(), - ), - "imports": ["site-packages"], - "deps": [ - "@pypi_bar_baz//:pkg", - "@pypi_foo//:pkg", - ] + _select( - { - Label("//python/config_settings:is_python_3.9"): ["@pypi_py39_dep//:pkg"], - "@platforms//cpu:aarch64": ["@pypi_arm_dep//:pkg"], - "@platforms//os:windows": ["@pypi_win_dep//:pkg"], - ":is_python_3.10_linux_ppc64le": ["@pypi_py310_linux_ppc64le_dep//:pkg"], - ":is_python_3.9_anyos_aarch64": ["@pypi_py39_arm_dep//:pkg"], - ":is_python_3.9_linux_anyarch": ["@pypi_py39_linux_dep//:pkg"], - ":is_linux_x86_64": ["@pypi_linux_intel_dep//:pkg"], - "//conditions:default": [], - }, - ), - "tags": ["tag1", "tag2"], - "visibility": ["//visibility:public"], - "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), - }, - ]) # buildifier: @unsorted-dict-items + + env.expect.that_collection(py_library_calls).has_size(1) + if len(py_library_calls) != 1: + return + 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"): [], + "//conditions:default": ["_create_inits_target"], + }), + "pyi_srcs": ["site-packages/foo/PYI.pyi"], + "data": ["site-packages/foo/DATA.txt"], + "imports": ["site-packages"], + "deps": [ + "@pypi_bar_baz//:pkg", + "@pypi_foo//:pkg", + ] + _select( + { + Label("//python/config_settings:is_python_3.9"): ["@pypi_py39_dep//:pkg"], + "@platforms//cpu:aarch64": ["@pypi_arm_dep//:pkg"], + "@platforms//os:windows": ["@pypi_win_dep//:pkg"], + ":is_python_3.10_linux_ppc64le": ["@pypi_py310_linux_ppc64le_dep//:pkg"], + ":is_python_3.9_anyos_aarch64": ["@pypi_py39_arm_dep//:pkg"], + ":is_python_3.9_linux_anyarch": ["@pypi_py39_linux_dep//:pkg"], + ":is_linux_x86_64": ["@pypi_linux_intel_dep//:pkg"], + "//conditions:default": [], + }, + ), + "tags": ["tag1", "tag2"], + "visibility": ["//visibility:public"], + "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), + }) # buildifier: @unsorted-dict-items _tests.append(_test_whl_and_library_deps) @@ -366,6 +384,11 @@ def _test_group(env): alias_calls = [] py_library_calls = [] + mock_glob = _mock_glob() + mock_glob.results.append(["site-packages/foo/srcs.py"]) + mock_glob.results.append(["site-packages/foo/data.txt"]) + mock_glob.results.append(["site-packages/foo/pyi.pyi"]) + whl_library_targets( name = "foo.whl", dep_template = "@pypi_{name}//:{target}", @@ -384,12 +407,13 @@ def _test_group(env): filegroups = {}, native = struct( config_setting = lambda **_: None, - glob = _glob, + glob = mock_glob.glob, alias = lambda **kwargs: alias_calls.append(kwargs), select = _select, ), rules = struct( py_library = lambda **kwargs: py_library_calls.append(kwargs), + create_inits = lambda **kwargs: ["_create_inits_target"], ), ) @@ -397,39 +421,69 @@ def _test_group(env): {"name": "pkg", "actual": "@pypi__groups//:qux_pkg", "visibility": ["//visibility:public"]}, {"name": "whl", "actual": "@pypi__groups//:qux_whl", "visibility": ["//visibility:public"]}, ]) # buildifier: @unsorted-dict-items - env.expect.that_collection(py_library_calls).contains_exactly([ - { - "name": "_pkg", - "srcs": _glob(["site-packages/**/*.py"], exclude = [], allow_empty = True), - "pyi_srcs": _glob(["site-packages/**/*.pyi"], allow_empty = True), - "data": [] + _glob( - ["site-packages/**/*"], - exclude = [ - "**/*.py", - "**/*.pyc", - "**/*.pyc.*", - "**/*.dist-info/RECORD", - ] + glob_excludes.version_dependent_exclusions(), - ), - "imports": ["site-packages"], - "deps": ["@pypi_bar_baz//:pkg"] + _select({ - "@platforms//os:linux": ["@pypi_box//:pkg"], - ":is_linux_x86_64": ["@pypi_box//:pkg", "@pypi_box_amd64//:pkg"], - "//conditions:default": [], - }), - "tags": [], - "visibility": ["@pypi__groups//:__pkg__"], - "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), - }, - ]) # buildifier: @unsorted-dict-items + + env.expect.that_collection(py_library_calls).has_size(1) + if len(py_library_calls) != 1: + return + + py_library_call = py_library_calls[0] + env.expect.where(case = "verify py library call").that_dict( + py_library_call, + ).contains_exactly({ + "name": "_pkg", + "srcs": ["site-packages/foo/srcs.py"] + _select({ + 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"], + "imports": ["site-packages"], + "deps": ["@pypi_bar_baz//:pkg"] + _select({ + "@platforms//os:linux": ["@pypi_box//:pkg"], + ":is_linux_x86_64": ["@pypi_box//:pkg", "@pypi_box_amd64//:pkg"], + "//conditions:default": [], + }), + "tags": [], + "visibility": ["@pypi__groups//:__pkg__"], + "experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"), + }) # buildifier: @unsorted-dict-items + + env.expect.that_collection(mock_glob.calls, expr = "glob calls").contains_exactly([ + _glob_call(["site-packages/**/*.py"], exclude = [], allow_empty = True), + _glob_call(["site-packages/**/*"], exclude = [ + "**/*.py", + "**/*.pyc", + "**/*.pyc.*", + "**/*.dist-info/RECORD", + ]), + _glob_call(["site-packages/**/*.pyi"], allow_empty = True), + ]) _tests.append(_test_group) -def _glob(*args, **kwargs): - return [struct( +def _glob_call(*args, **kwargs): + return struct( glob = args, kwargs = kwargs, - )] + ) + +def _mock_glob(): + # buildifier: disable=uninitialized + def glob(*args, **kwargs): + mock.calls.append(_glob_call(*args, **kwargs)) + if not mock.results: + fail("Mock glob missing for invocation: args={} kwargs={}".format( + args, + kwargs, + )) + return mock.results.pop(0) + + mock = struct( + calls = [], + results = [], + glob = glob, + ) + return mock def _select(*args, **kwargs): """We need to have this mock select because we still need to support bazel 6."""