# Copyright 2024 The Bazel Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. "" load("@rules_testing//lib:test_suite.bzl", "test_suite") load("@rules_testing//lib:truth.bzl", "subjects") load("//python/private/pypi:extension.bzl", "parse_modules") # buildifier: disable=bzl-visibility load("//python/private/pypi:whl_config_setting.bzl", "whl_config_setting") # buildifier: disable=bzl-visibility _tests = [] def _mock_mctx(*modules, environ = {}, read = None): return struct( os = struct( environ = environ, name = "unittest", arch = "exotic", ), read = read or (lambda _: "simple==0.0.1 --hash=sha256:deadbeef --hash=sha256:deadbaaf"), modules = [ struct( name = modules[0].name, tags = modules[0].tags, is_root = modules[0].is_root, ), ] + [ struct( name = mod.name, tags = mod.tags, is_root = False, ) for mod in modules[1:] ], ) def _mod(*, name, parse = [], override = [], whl_mods = [], is_root = True): return struct( name = name, tags = struct( parse = parse, override = override, whl_mods = whl_mods, ), is_root = is_root, ) def _parse_modules(env, **kwargs): return env.expect.that_struct( parse_modules(**kwargs), attrs = dict( is_reproducible = subjects.bool, exposed_packages = subjects.dict, hub_group_map = subjects.dict, hub_whl_map = subjects.dict, whl_libraries = subjects.dict, whl_mods = subjects.dict, ), ) def _parse( *, hub_name, python_version, _evaluate_markers_srcs = [], auth_patterns = {}, download_only = False, enable_implicit_namespace_pkgs = False, environment = {}, envsubst = {}, experimental_index_url = "", experimental_requirement_cycles = {}, experimental_target_platforms = [], extra_hub_aliases = {}, extra_pip_args = [], isolated = True, netrc = None, parse_all_requirements_files = True, pip_data_exclude = None, python_interpreter = None, python_interpreter_target = None, quiet = True, requirements_by_platform = {}, requirements_darwin = None, requirements_linux = None, requirements_lock = None, requirements_windows = None, timeout = 600, whl_modifications = {}, **kwargs): return struct( _evaluate_markers_srcs = _evaluate_markers_srcs, auth_patterns = auth_patterns, download_only = download_only, enable_implicit_namespace_pkgs = enable_implicit_namespace_pkgs, environment = environment, envsubst = envsubst, experimental_index_url = experimental_index_url, experimental_requirement_cycles = experimental_requirement_cycles, experimental_target_platforms = experimental_target_platforms, extra_hub_aliases = extra_hub_aliases, extra_pip_args = extra_pip_args, hub_name = hub_name, isolated = isolated, netrc = netrc, parse_all_requirements_files = parse_all_requirements_files, pip_data_exclude = pip_data_exclude, python_interpreter = python_interpreter, python_interpreter_target = python_interpreter_target, python_version = python_version, quiet = quiet, requirements_by_platform = requirements_by_platform, requirements_darwin = requirements_darwin, requirements_linux = requirements_linux, requirements_lock = requirements_lock, requirements_windows = requirements_windows, timeout = timeout, whl_modifications = whl_modifications, # The following are covered by other unit tests experimental_extra_index_urls = [], parallel_download = False, experimental_index_url_overrides = {}, **kwargs ) def _test_simple(env): pypi = _parse_modules( env, module_ctx = _mock_mctx( _mod( name = "rules_python", parse = [ _parse( hub_name = "pypi", python_version = "3.15", requirements_lock = "requirements.txt", ), ], ), ), available_interpreters = { "python_3_15_host": "unit_test_interpreter_target", }, ) pypi.is_reproducible().equals(True) pypi.exposed_packages().contains_exactly({"pypi": ["simple"]}) pypi.hub_group_map().contains_exactly({"pypi": {}}) pypi.hub_whl_map().contains_exactly({"pypi": { "simple": { "pypi_315_simple": [ whl_config_setting( version = "3.15", ), ], }, }}) pypi.whl_libraries().contains_exactly({ "pypi_315_simple": { "dep_template": "@pypi//{name}:{target}", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.1 --hash=sha256:deadbeef --hash=sha256:deadbaaf", }, }) pypi.whl_mods().contains_exactly({}) _tests.append(_test_simple) def _test_simple_multiple_requirements(env): pypi = _parse_modules( env, module_ctx = _mock_mctx( _mod( name = "rules_python", parse = [ _parse( hub_name = "pypi", python_version = "3.15", requirements_darwin = "darwin.txt", requirements_windows = "win.txt", ), ], ), read = lambda x: { "darwin.txt": "simple==0.0.2 --hash=sha256:deadb00f", "win.txt": "simple==0.0.1 --hash=sha256:deadbeef", }[x], ), available_interpreters = { "python_3_15_host": "unit_test_interpreter_target", }, ) pypi.is_reproducible().equals(True) pypi.exposed_packages().contains_exactly({"pypi": ["simple"]}) pypi.hub_group_map().contains_exactly({"pypi": {}}) pypi.hub_whl_map().contains_exactly({"pypi": { "simple": { "pypi_315_simple_osx_aarch64_osx_x86_64": [ whl_config_setting( target_platforms = [ "cp315_osx_aarch64", "cp315_osx_x86_64", ], version = "3.15", ), ], "pypi_315_simple_windows_x86_64": [ whl_config_setting( target_platforms = [ "cp315_windows_x86_64", ], version = "3.15", ), ], }, }}) pypi.whl_libraries().contains_exactly({ "pypi_315_simple_osx_aarch64_osx_x86_64": { "dep_template": "@pypi//{name}:{target}", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.2 --hash=sha256:deadb00f", }, "pypi_315_simple_windows_x86_64": { "dep_template": "@pypi//{name}:{target}", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.1 --hash=sha256:deadbeef", }, }) pypi.whl_mods().contains_exactly({}) _tests.append(_test_simple_multiple_requirements) def _test_simple_with_markers(env): pypi = _parse_modules( env, module_ctx = _mock_mctx( _mod( name = "rules_python", parse = [ _parse( hub_name = "pypi", python_version = "3.15", requirements_lock = "universal.txt", ), ], ), read = lambda x: { "universal.txt": """\ torch==2.4.1+cpu ; platform_machine == 'x86_64' torch==2.4.1 ; platform_machine != 'x86_64' """, }[x], ), available_interpreters = { "python_3_15_host": "unit_test_interpreter_target", }, evaluate_markers = lambda _, requirements, **__: { key: [ platform for platform in platforms if ("x86_64" in platform and "platform_machine ==" in key) or ("x86_64" not in platform and "platform_machine !=" in key) ] for key, platforms in requirements.items() }, ) pypi.is_reproducible().equals(True) pypi.exposed_packages().contains_exactly({"pypi": ["torch"]}) pypi.hub_group_map().contains_exactly({"pypi": {}}) pypi.hub_whl_map().contains_exactly({"pypi": { "torch": { "pypi_315_torch_linux_aarch64_linux_arm_linux_ppc_linux_s390x_osx_aarch64": [ whl_config_setting( target_platforms = [ "cp315_linux_aarch64", "cp315_linux_arm", "cp315_linux_ppc", "cp315_linux_s390x", "cp315_osx_aarch64", ], version = "3.15", ), ], "pypi_315_torch_linux_x86_64_osx_x86_64_windows_x86_64": [ whl_config_setting( target_platforms = [ "cp315_linux_x86_64", "cp315_osx_x86_64", "cp315_windows_x86_64", ], version = "3.15", ), ], }, }}) pypi.whl_libraries().contains_exactly({ "pypi_315_torch_linux_aarch64_linux_arm_linux_ppc_linux_s390x_osx_aarch64": { "dep_template": "@pypi//{name}:{target}", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "torch==2.4.1 ; platform_machine != 'x86_64'", }, "pypi_315_torch_linux_x86_64_osx_x86_64_windows_x86_64": { "dep_template": "@pypi//{name}:{target}", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "torch==2.4.1+cpu ; platform_machine == 'x86_64'", }, }) pypi.whl_mods().contains_exactly({}) _tests.append(_test_simple_with_markers) def _test_download_only_multiple(env): pypi = _parse_modules( env, module_ctx = _mock_mctx( _mod( name = "rules_python", parse = [ _parse( hub_name = "pypi", python_version = "3.15", download_only = True, requirements_by_platform = { "requirements.linux_x86_64.txt": "linux_x86_64", "requirements.osx_aarch64.txt": "osx_aarch64", }, ), ], ), read = lambda x: { "requirements.linux_x86_64.txt": """\ --platform=manylinux_2_17_x86_64 --python-version=315 --implementation=cp --abi=cp315 simple==0.0.1 --hash=sha256:deadbeef extra==0.0.1 --hash=sha256:deadb00f """, "requirements.osx_aarch64.txt": """\ --platform=macosx_10_9_arm64 --python-version=315 --implementation=cp --abi=cp315 simple==0.0.3 --hash=sha256:deadbaaf """, }[x], ), available_interpreters = { "python_3_15_host": "unit_test_interpreter_target", }, ) pypi.is_reproducible().equals(True) pypi.exposed_packages().contains_exactly({"pypi": ["simple"]}) pypi.hub_group_map().contains_exactly({"pypi": {}}) pypi.hub_whl_map().contains_exactly({"pypi": { "extra": { "pypi_315_extra": [ whl_config_setting(version = "3.15"), ], }, "simple": { "pypi_315_simple_linux_x86_64": [ whl_config_setting( target_platforms = ["cp315_linux_x86_64"], version = "3.15", ), ], "pypi_315_simple_osx_aarch64": [ whl_config_setting( target_platforms = ["cp315_osx_aarch64"], version = "3.15", ), ], }, }}) pypi.whl_libraries().contains_exactly({ "pypi_315_extra": { "dep_template": "@pypi//{name}:{target}", "download_only": True, "experimental_target_platforms": ["cp315_linux_x86_64"], "extra_pip_args": ["--platform=manylinux_2_17_x86_64", "--python-version=315", "--implementation=cp", "--abi=cp315"], "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "extra==0.0.1 --hash=sha256:deadb00f", }, "pypi_315_simple_linux_x86_64": { "dep_template": "@pypi//{name}:{target}", "download_only": True, "experimental_target_platforms": ["cp315_linux_x86_64"], "extra_pip_args": ["--platform=manylinux_2_17_x86_64", "--python-version=315", "--implementation=cp", "--abi=cp315"], "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.1 --hash=sha256:deadbeef", }, "pypi_315_simple_osx_aarch64": { "dep_template": "@pypi//{name}:{target}", "download_only": True, "experimental_target_platforms": ["cp315_osx_aarch64"], "extra_pip_args": ["--platform=macosx_10_9_arm64", "--python-version=315", "--implementation=cp", "--abi=cp315"], "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.3 --hash=sha256:deadbaaf", }, }) pypi.whl_mods().contains_exactly({}) _tests.append(_test_download_only_multiple) def _test_simple_get_index(env): got_simpleapi_download_args = [] got_simpleapi_download_kwargs = {} def mocksimpleapi_download(*args, **kwargs): got_simpleapi_download_args.extend(args) got_simpleapi_download_kwargs.update(kwargs) return { "simple": struct( whls = { "deadb00f": struct( yanked = False, filename = "simple-0.0.1-py3-none-any.whl", sha256 = "deadb00f", url = "example2.org", ), }, sdists = { "deadbeef": struct( yanked = False, filename = "simple-0.0.1.tar.gz", sha256 = "deadbeef", url = "example.org", ), }, ), } pypi = _parse_modules( env, module_ctx = _mock_mctx( _mod( name = "rules_python", parse = [ _parse( hub_name = "pypi", python_version = "3.15", requirements_lock = "requirements.txt", experimental_index_url = "pypi.org", extra_pip_args = [ "--extra-args-for-sdist-building", ], ), ], ), read = lambda x: { "requirements.txt": """ simple==0.0.1 --hash=sha256:deadbeef --hash=sha256:deadb00f some_pkg==0.0.1 """, }[x], ), available_interpreters = { "python_3_15_host": "unit_test_interpreter_target", }, simpleapi_download = mocksimpleapi_download, ) pypi.is_reproducible().equals(False) pypi.exposed_packages().contains_exactly({"pypi": ["simple", "some_pkg"]}) pypi.hub_group_map().contains_exactly({"pypi": {}}) pypi.hub_whl_map().contains_exactly({ "pypi": { "simple": { "pypi_315_simple_py3_none_any_deadb00f": [ whl_config_setting( filename = "simple-0.0.1-py3-none-any.whl", version = "3.15", ), ], "pypi_315_simple_sdist_deadbeef": [ whl_config_setting( filename = "simple-0.0.1.tar.gz", version = "3.15", ), ], }, "some_pkg": { "pypi_315_some_pkg": [whl_config_setting(version = "3.15")], }, }, }) pypi.whl_libraries().contains_exactly({ "pypi_315_simple_py3_none_any_deadb00f": { "dep_template": "@pypi//{name}:{target}", "experimental_target_platforms": [ "cp315_linux_aarch64", "cp315_linux_arm", "cp315_linux_ppc", "cp315_linux_s390x", "cp315_linux_x86_64", "cp315_osx_aarch64", "cp315_osx_x86_64", "cp315_windows_x86_64", ], "filename": "simple-0.0.1-py3-none-any.whl", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.1", "sha256": "deadb00f", "urls": ["example2.org"], }, "pypi_315_simple_sdist_deadbeef": { "dep_template": "@pypi//{name}:{target}", "experimental_target_platforms": [ "cp315_linux_aarch64", "cp315_linux_arm", "cp315_linux_ppc", "cp315_linux_s390x", "cp315_linux_x86_64", "cp315_osx_aarch64", "cp315_osx_x86_64", "cp315_windows_x86_64", ], "extra_pip_args": ["--extra-args-for-sdist-building"], "filename": "simple-0.0.1.tar.gz", "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "simple==0.0.1", "sha256": "deadbeef", "urls": ["example.org"], }, # We are falling back to regular `pip` "pypi_315_some_pkg": { "dep_template": "@pypi//{name}:{target}", "extra_pip_args": ["--extra-args-for-sdist-building"], "python_interpreter_target": "unit_test_interpreter_target", "repo": "pypi_315", "requirement": "some_pkg==0.0.1", }, }) pypi.whl_mods().contains_exactly({}) env.expect.that_dict(got_simpleapi_download_kwargs).contains_exactly({ "attr": struct( auth_patterns = {}, envsubst = {}, extra_index_urls = [], index_url = "pypi.org", index_url_overrides = {}, netrc = None, sources = ["simple", "some_pkg"], ), "cache": {}, "parallel_download": False, }) _tests.append(_test_simple_get_index) def extension_test_suite(name): """Create the test suite. Args: name: the name of the test suite """ test_suite(name = name, basic_tests = _tests)