1# Copyright 2024 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Starlark tests for PyRuntimeInfo provider.""" 15 16load("@rules_testing//lib:analysis_test.bzl", "analysis_test") 17load("@rules_testing//lib:test_suite.bzl", "test_suite") 18load("@rules_testing//lib:util.bzl", rt_util = "util") 19load("//python:py_runtime.bzl", "py_runtime") 20load("//python:py_runtime_pair.bzl", "py_runtime_pair") 21load("//python/private:toolchain_types.bzl", "EXEC_TOOLS_TOOLCHAIN_TYPE", "TARGET_TOOLCHAIN_TYPE") # buildifier: disable=bzl-visibility 22load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER") # buildifier: disable=bzl-visibility 23load("//tests/support:support.bzl", "LINUX", "MAC", "PYTHON_VERSION") 24 25_LookupInfo = provider() # buildifier: disable=provider-params 26 27def _lookup_toolchains_impl(ctx): 28 return [_LookupInfo( 29 target = ctx.toolchains[TARGET_TOOLCHAIN_TYPE], 30 exec = ctx.toolchains[EXEC_TOOLS_TOOLCHAIN_TYPE], 31 )] 32 33_lookup_toolchains = rule( 34 implementation = _lookup_toolchains_impl, 35 toolchains = [TARGET_TOOLCHAIN_TYPE, EXEC_TOOLS_TOOLCHAIN_TYPE], 36 attrs = {"_use_auto_exec_groups": attr.bool(default = True)}, 37) 38 39def define_py_runtime(name, **kwargs): 40 py_runtime( 41 name = name + "_runtime", 42 **kwargs 43 ) 44 py_runtime_pair( 45 name = name, 46 py3_runtime = name + "_runtime", 47 ) 48 49_tests = [] 50 51def _test_exec_matches_target_python_version(name): 52 rt_util.helper_target( 53 _lookup_toolchains, 54 name = name + "_subject", 55 ) 56 57 # ==== Target toolchains ===== 58 59 # This is never matched. It comes first to ensure the python version 60 # constraint is being respected. 61 native.toolchain( 62 name = "00_target_3.11_any", 63 toolchain_type = TARGET_TOOLCHAIN_TYPE, 64 toolchain = ":target_3.12_linux", 65 target_settings = ["//python/config_settings:is_python_3.11"], 66 ) 67 68 # This is matched by the top-level target being built in what --platforms 69 # specifies. 70 native.toolchain( 71 name = "10_target_3.12_linux", 72 toolchain_type = TARGET_TOOLCHAIN_TYPE, 73 toolchain = ":target_3.12_linux", 74 target_compatible_with = ["@platforms//os:linux"], 75 target_settings = ["//python/config_settings:is_python_3.12"], 76 ) 77 78 # This is matched when the exec config switches to the mac platform and 79 # then looks for a Python runtime for itself. 80 native.toolchain( 81 name = "15_target_3.12_mac", 82 toolchain_type = TARGET_TOOLCHAIN_TYPE, 83 toolchain = ":target_3.12_mac", 84 target_compatible_with = ["@platforms//os:macos"], 85 target_settings = ["//python/config_settings:is_python_3.12"], 86 ) 87 88 # This is never matched. It's just here so that toolchains from the 89 # environment don't match. 90 native.toolchain( 91 name = "99_target_default", 92 toolchain_type = TARGET_TOOLCHAIN_TYPE, 93 toolchain = ":target_default", 94 ) 95 96 # ==== Exec tools toolchains ===== 97 98 # Register a 3.11 before to ensure it the python version is respected 99 native.toolchain( 100 name = "00_exec_3.11_any", 101 toolchain_type = EXEC_TOOLS_TOOLCHAIN_TYPE, 102 toolchain = ":exec_3.11_any", 103 target_settings = ["//python/config_settings:is_python_3.11"], 104 ) 105 106 # Note that mac comes first. This is so it matches instead of linux 107 # We only ever look for mac ones, so no need to register others. 108 native.toolchain( 109 name = "10_exec_3.12_mac", 110 toolchain_type = EXEC_TOOLS_TOOLCHAIN_TYPE, 111 toolchain = ":exec_3.12", 112 exec_compatible_with = ["@platforms//os:macos"], 113 target_settings = ["//python/config_settings:is_python_3.12"], 114 ) 115 116 # This is never matched. It's just here so that toolchains from the 117 # environment don't match. 118 native.toolchain( 119 name = "99_exec_default", 120 toolchain_type = EXEC_TOOLS_TOOLCHAIN_TYPE, 121 toolchain = ":exec_default", 122 ) 123 124 analysis_test( 125 name = name, 126 target = name + "_subject", 127 impl = _test_exec_matches_target_python_version_impl, 128 config_settings = { 129 "//command_line_option:extra_execution_platforms": [str(MAC)], 130 "//command_line_option:extra_toolchains": ["//tests/exec_toolchain_matching:all"], 131 "//command_line_option:platforms": [str(LINUX)], 132 PYTHON_VERSION: "3.12", 133 }, 134 ) 135 136_tests.append(_test_exec_matches_target_python_version) 137 138def _test_exec_matches_target_python_version_impl(env, target): 139 target_runtime = target[_LookupInfo].target.py3_runtime 140 exec_runtime = target[_LookupInfo].exec.exec_tools.exec_interpreter[platform_common.ToolchainInfo].py3_runtime 141 142 env.expect.that_str(target_runtime.interpreter_path).equals("/linux/python3.12") 143 env.expect.that_str(exec_runtime.interpreter_path).equals("/mac/python3.12") 144 145 if IS_BAZEL_7_OR_HIGHER: 146 target_version = target_runtime.interpreter_version_info 147 exec_version = exec_runtime.interpreter_version_info 148 149 env.expect.that_bool(target_version == exec_version) 150 151def exec_toolchain_matching_test_suite(name): 152 test_suite(name = name, tests = _tests) 153