diff --git a/MODULE.bazel b/MODULE.bazel index b45f69d..d4fa2ac 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -18,21 +18,46 @@ register_toolchains("@mojo_toolchains//...", "@mojo_gpu_toolchains//...") _DEFAULT_PYTHON_VERSION = "3.12" +_PYTHON_VERSIONS = [ + "3.9", + "3.10", + "3.11", + "3.12", + "3.13", +] + python = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency = True) -python.toolchain( - ignore_root_user_error = True, - is_default = True, - python_version = _DEFAULT_PYTHON_VERSION, -) + +[ + python.toolchain( + ignore_root_user_error = True, + is_default = version == _DEFAULT_PYTHON_VERSION, + python_version = version, + ) + for version in _PYTHON_VERSIONS +] pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) -pip.parse( - hub_name = "rules_mojo_test_deps", - python_version = _DEFAULT_PYTHON_VERSION, - requirements_lock = "tests/python/requirements.txt", -) + +[ + pip.parse( + hub_name = "rules_mojo_test_deps", + python_version = version, + requirements_lock = "tests/python/requirements.txt", + ) + for version in _PYTHON_VERSIONS +] + use_repo(pip, "rules_mojo_test_deps") +versions = use_repo_rule("//tests:versions.bzl", "versions") + +versions( + name = "versions", + dev_dependency = True, + python_versions = _PYTHON_VERSIONS, +) + link_hack = use_repo_rule("//mojo/private:link_hack.bzl", "link_hack") link_hack( diff --git a/mojo/private/mojo_binary_test.bzl b/mojo/private/mojo_binary_test.bzl index f772559..36975cc 100644 --- a/mojo/private/mojo_binary_test.bzl +++ b/mojo/private/mojo_binary_test.bzl @@ -6,6 +6,7 @@ load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_c load("@build_bazel_rules_android//:link_hack.bzl", "link_hack") # See link_hack.bzl for details load("@rules_python//python:py_info.bzl", "PyInfo") load("//mojo:providers.bzl", "MojoInfo") +load(":transitions.bzl", "python_version_transition") load(":utils.bzl", "MOJO_EXTENSIONS", "collect_mojoinfo") _PYTHON_TOOLCHAIN_TYPE = "@rules_python//python:toolchain_type" @@ -24,6 +25,9 @@ _ATTRS = { "data": attr.label_list(allow_files = True), "enable_assertions": attr.bool(default = True), "env": attr.string_dict(), + "python_version": attr.string( + doc = "The version of Python to use for this target and all its dependencies.", + ), "_mojo_copts": attr.label( default = Label("//:mojo_copt"), ), @@ -192,10 +196,12 @@ def _mojo_binary_test_implementation(ctx, *, shared_library = False): if not libpython: fail("failed to find libpython, please report this at https://github.com/modular/rules_mojo/issues") + default_path = ctx.attr.env.get("PATH") or ctx.configuration.default_shell_env.get("PATH") or "/usr/bin:/bin:/usr/sbin" runtime_env = dict(ctx.attr.env) | { "MODULAR_PYTHON_EXECUTABLE": py_toolchain.py3_runtime.interpreter.short_path, "MOJO_PYTHON": py_toolchain.py3_runtime.interpreter.short_path, "MOJO_PYTHON_LIBRARY": libpython, + "PATH": paths.dirname(py_toolchain.py3_runtime.interpreter.short_path) + ":" + default_path, # python < 3.11 doesn't set sys.executable correctly when Py_Initialize is called unless it's in the $PATH "PYTHONEXECUTABLE": py_toolchain.py3_runtime.interpreter.short_path, "PYTHONNOUSERSITE": "affirmative", "PYTHONPATH": python_path, @@ -257,6 +263,7 @@ mojo_test = rule( toolchains = _TOOLCHAINS, fragments = ["cpp"], test = True, + cfg = python_version_transition, ) mojo_shared_library = rule( diff --git a/mojo/private/transitions.bzl b/mojo/private/transitions.bzl new file mode 100644 index 0000000..02ffba9 --- /dev/null +++ b/mojo/private/transitions.bzl @@ -0,0 +1,15 @@ +"""Transitions used by Mojo rules.""" + +_PYTHON_VERSION = "@rules_python//python/config_settings:python_version" + +def _python_version_transition_impl(settings, attr): + output = {_PYTHON_VERSION: settings[_PYTHON_VERSION]} + if attr.python_version: + output["@rules_python//python/config_settings:python_version"] = str(attr.python_version) + return output + +python_version_transition = transition( + implementation = _python_version_transition_impl, + inputs = [_PYTHON_VERSION], + outputs = [_PYTHON_VERSION], +) diff --git a/tests/python/BUILD.bazel b/tests/python/BUILD.bazel index 4ce810d..b386c4d 100644 --- a/tests/python/BUILD.bazel +++ b/tests/python/BUILD.bazel @@ -1,12 +1,18 @@ load("@rules_mojo_test_deps//:requirements.bzl", "requirement") load("@rules_python//python:defs.bzl", "py_test") +load("@versions//:config.bzl", "PYTHON_VERSIONS") load("//mojo:mojo_shared_library.bzl", "mojo_shared_library") load("//mojo:mojo_test.bzl", "mojo_test") -mojo_test( - name = "basic_python_test", - srcs = ["basic_python_test.mojo"], -) +[ + mojo_test( + name = "basic_python_test_py_" + version.replace(".", "_"), + srcs = ["basic_python_test.mojo"], + env = {"EXPECTED_PYTHON_VERSION": version}, + python_version = version, + ) + for version in PYTHON_VERSIONS +] mojo_test( name = "deps_python_test", diff --git a/tests/python/basic_python_test.mojo b/tests/python/basic_python_test.mojo index d5450a8..6ff74f2 100644 --- a/tests/python/basic_python_test.mojo +++ b/tests/python/basic_python_test.mojo @@ -1,7 +1,11 @@ from python import Python +from os import getenv from testing import assert_true def main(): sys = Python.import_module("sys") print("Python executable:", sys.executable) + print("Python version:", sys.version) + assert_true(sys.version.startswith(getenv("EXPECTED_PYTHON_VERSION"))) assert_true(not sys.executable.startswith("/usr")) + assert_true(not sys.executable.startswith("/bin")) diff --git a/tests/python/requirements.txt b/tests/python/requirements.txt index f7857aa..b0a8fb5 100644 --- a/tests/python/requirements.txt +++ b/tests/python/requirements.txt @@ -1,34 +1,49 @@ # This file was autogenerated by uv via the following command: -# uv export -o requirements.txt -numpy==2.2.5 \ - --hash=sha256:02f226baeefa68f7d579e213d0f3493496397d8f1cff5e2b222af274c86a552a \ - --hash=sha256:059b51b658f4414fff78c6d7b1b4e18283ab5fa56d270ff212d5ba0c561846f4 \ - --hash=sha256:0cd48122a6b7eab8f06404805b1bd5856200e3ed6f8a1b9a194f9d9054631beb \ - --hash=sha256:1a161c2c79ab30fe4501d5a2bbfe8b162490757cf90b7f05be8b80bc02f7bb8e \ - --hash=sha256:261a1ef047751bb02f29dfe337230b5882b54521ca121fc7f62668133cb119c9 \ - --hash=sha256:2ba321813a00e508d5421104464510cc962a6f791aa2fca1c97b1e65027da80d \ - --hash=sha256:2c1a1c6ccce4022383583a6ded7bbcda22fc635eb4eb1e0a053336425ed36dfa \ - --hash=sha256:352d330048c055ea6db701130abc48a21bec690a8d38f8284e00fab256dc1376 \ - --hash=sha256:3a801fef99668f309b88640e28d261991bfad9617c27beda4a3aec4f217ea073 \ - --hash=sha256:3d14b17b9be5f9c9301f43d2e2a4886a33b53f4e6fdf9ca2f4cc60aeeee76372 \ - --hash=sha256:4520caa3807c1ceb005d125a75e715567806fed67e315cea619d5ec6e75a4191 \ - --hash=sha256:47834cde750d3c9f4e52c6ca28a7361859fcaf52695c7dc3cc1a720b8922683e \ - --hash=sha256:47f9ed103af0bc63182609044b0490747e03bd20a67e391192dde119bf43d52f \ - --hash=sha256:54088a5a147ab71a8e7fdfd8c3601972751ded0739c6b696ad9cb0343e21ab73 \ - --hash=sha256:55f09e00d4dccd76b179c0f18a44f041e5332fd0e022886ba1c0bbf3ea4a18d0 \ - --hash=sha256:5a0ac90e46fdb5649ab6369d1ab6104bfe5854ab19b645bf5cda0127a13034ae \ - --hash=sha256:8b4c0773b6ada798f51f0f8e30c054d32304ccc6e9c5d93d46cb26f3d385ab19 \ - --hash=sha256:8dfa94b6a4374e7851bbb6f35e6ded2120b752b063e6acdd3157e4d2bb922eba \ - --hash=sha256:97c8425d4e26437e65e1d189d22dff4a079b747ff9c2788057bfb8114ce1e133 \ - --hash=sha256:9d75f338f5f79ee23548b03d801d28a505198297534f62416391857ea0479571 \ - --hash=sha256:a4cbdef3ddf777423060c6f81b5694bad2dc9675f110c4b2a60dc0181543fac7 \ - --hash=sha256:a9c0d994680cd991b1cb772e8b297340085466a6fe964bc9d4e80f5e2f43c291 \ - --hash=sha256:abe38cd8381245a7f49967a6010e77dbf3680bd3627c0fe4362dd693b404c7f8 \ - --hash=sha256:c26843fd58f65da9491165072da2cccc372530681de481ef670dcc8e27cfb066 \ - --hash=sha256:c8b82a55ef86a2d8e81b63da85e55f5537d2157165be1cb2ce7cfa57b6aef38b \ - --hash=sha256:ced69262a8278547e63409b2653b372bf4baff0870c57efa76c5703fd6543282 \ - --hash=sha256:d403c84991b5ad291d3809bace5e85f4bbf44a04bdc9a88ed2bb1807b3360bb8 \ - --hash=sha256:d8882a829fd779f0f43998e931c466802a77ca1ee0fe25a3abe50278616b1471 \ - --hash=sha256:e8b025c351b9f0e8b5436cf28a07fa4ac0204d67b38f01433ac7f9b870fa38c6 \ - --hash=sha256:ec31367fd6a255dc8de4772bd1658c3e926d8e860a0b6e922b615e532d320ddc \ - --hash=sha256:ee461a4eaab4f165b68780a6a1af95fb23a29932be7569b9fab666c407969051 +# uv pip compile /tmp/requirements.txt --python-version 3.9 --generate-hashes +numpy==2.0.2 \ + --hash=sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a \ + --hash=sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195 \ + --hash=sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951 \ + --hash=sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1 \ + --hash=sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c \ + --hash=sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc \ + --hash=sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b \ + --hash=sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd \ + --hash=sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4 \ + --hash=sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd \ + --hash=sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318 \ + --hash=sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448 \ + --hash=sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece \ + --hash=sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d \ + --hash=sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5 \ + --hash=sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8 \ + --hash=sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57 \ + --hash=sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78 \ + --hash=sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66 \ + --hash=sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a \ + --hash=sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e \ + --hash=sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c \ + --hash=sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa \ + --hash=sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d \ + --hash=sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c \ + --hash=sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729 \ + --hash=sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97 \ + --hash=sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c \ + --hash=sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9 \ + --hash=sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669 \ + --hash=sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4 \ + --hash=sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73 \ + --hash=sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385 \ + --hash=sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8 \ + --hash=sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c \ + --hash=sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b \ + --hash=sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692 \ + --hash=sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15 \ + --hash=sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131 \ + --hash=sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a \ + --hash=sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326 \ + --hash=sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b \ + --hash=sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded \ + --hash=sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04 \ + --hash=sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd + # via -r /tmp/requirements.txt diff --git a/tests/versions.bzl b/tests/versions.bzl new file mode 100644 index 0000000..0086620 --- /dev/null +++ b/tests/versions.bzl @@ -0,0 +1,16 @@ +"""A repo rule to expose constants that have to be hardcoded in the MODULE.bazel to other bzl files.""" + +def _impl(rctx): + rctx.file("BUILD.bazel", "") + rctx.file("config.bzl", """\ +PYTHON_VERSIONS = {python_versions} +""".format( + python_versions = str(rctx.attr.python_versions), + )) + +versions = repository_rule( + implementation = _impl, + attrs = { + "python_versions": attr.string_list(mandatory = True), + }, +)