From 96c6774611655a97bd6118b43d89cb3ab9efed84 Mon Sep 17 00:00:00 2001 From: Reid D McKenzie Date: Tue, 11 Nov 2025 13:30:38 -0500 Subject: [PATCH 1/6] [NO TESTS] WIP --- py/BUILD.bazel | 11 +++++++++++ py/private/py_venv/link.py | 2 -- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/py/BUILD.bazel b/py/BUILD.bazel index d12225d2..86afc777 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -1,4 +1,5 @@ load("@aspect_bazel_lib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") # For Bazel 6.x compatibility, since # PyRuntimeInfo shipped only with Bazel 7 @@ -9,6 +10,16 @@ alias( visibility = ["//visibility:public"], ) +string_flag( + name = "venv_strategy", + build_setting_default = "dynamic", + values = [ + "dynamic", + "static", + ], + visibility = ["//visibility:public"], +) + bzl_library( name = "repositories", srcs = ["repositories.bzl"], diff --git a/py/private/py_venv/link.py b/py/private/py_venv/link.py index 28748e81..9b9cbbca 100644 --- a/py/private/py_venv/link.py +++ b/py/private/py_venv/link.py @@ -7,8 +7,6 @@ import argparse import os -import sys -import site from pathlib import Path From 4a1b068bb80b731b6012ac36f1801111052b0e72 Mon Sep 17 00:00:00 2001 From: "Reid D. McKenzie" Date: Wed, 12 Nov 2025 11:40:07 -0500 Subject: [PATCH 2/6] feat(venv): Make the venv strategy configurable --- py/BUILD.bazel | 18 +++------- py/defs.bzl | 49 +++++++++++++++++++++++----- py/private/link/BUILD.bazel | 41 +++++++++++++++++++++++ py/private/link/defs.bzl | 46 ++++++++++++++++++++++++++ py/private/{py_venv => link}/link.py | 1 - py/private/py_venv/defs.bzl | 3 +- py/private/py_venv/py_venv.bzl | 16 --------- py/settings/BUILD.bazel | 21 ++++++++++++ py/unstable/defs.bzl | 3 +- 9 files changed, 154 insertions(+), 44 deletions(-) create mode 100644 py/private/link/BUILD.bazel create mode 100644 py/private/link/defs.bzl rename py/private/{py_venv => link}/link.py (97%) create mode 100644 py/settings/BUILD.bazel diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 86afc777..e3d46776 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -1,23 +1,11 @@ load("@aspect_bazel_lib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "string_flag") -# For Bazel 6.x compatibility, since -# PyRuntimeInfo shipped only with Bazel 7 -# Users can set, e.g. --@aspect_rules_py//py:interpreter_version=3.9.18 alias( name = "interpreter_version", - actual = "@rules_python//python/config_settings:python_version", - visibility = ["//visibility:public"], -) - -string_flag( - name = "venv_strategy", - build_setting_default = "dynamic", - values = [ - "dynamic", - "static", - ], + actual = "//py/settings:interpreter_version", visibility = ["//visibility:public"], + deprecation = "Please prefer py/settings:interpreter_version", ) bzl_library( @@ -46,12 +34,14 @@ bzl_library( "//py/private:py_wheel", "//py/private:virtual", "//py/private/py_venv", + "//py/private/link", "@aspect_bazel_lib//lib:utils", ], ) # This needs to dep on @aspect_tools_telemetry_report but we don't have that in WORKSPACE # gazelle:exclude extensions.bzl +# # bzl_library( # name = "extensions", # srcs = [ diff --git a/py/defs.bzl b/py/defs.bzl index bc9ff216..5ac019f5 100644 --- a/py/defs.bzl +++ b/py/defs.bzl @@ -42,14 +42,48 @@ load("//py/private:py_pex_binary.bzl", _py_pex_binary = "py_pex_binary") load("//py/private:py_pytest_main.bzl", _py_pytest_main = "py_pytest_main") load("//py/private:py_unpacked_wheel.bzl", _py_unpacked_wheel = "py_unpacked_wheel") load("//py/private:virtual.bzl", _resolutions = "resolutions") -load("//py/private/py_venv:defs.bzl", _py_venv_link = "py_venv_link") +load("//py/private/py_venv:defs.bzl", _py_venv_binary = "py_venv_binary") +load("//py/private/link:defs.bzl", _py_link_venv = "py_link_venv") py_pex_binary = _py_pex_binary py_pytest_main = _py_pytest_main # FIXME: Badly chosen name; will be replaced/migrated -py_venv = _py_venv_link -py_venv_link = _py_venv_link +def py_venv(name, srcs = [], data = [], deps = [], imports = None, testonly = False, **kwargs): + native.alias( + name = name, + actual = select({ + Label("//py/private/link:dynamic_venvs"): ":{}_dynamic".format(name), + Label("//py/private/link:static_venvs"): ":{}_static".format(name), + }), + tags = ["manual"], + ) + + _py_link_venv( + _py_binary, + name = "{}_dynamic".format(name), + srcs = srcs, + data = data, + deps = deps, + imports = kwargs.get("imports"), + tags = ["manual"], + testonly = kwargs.get("testonly", False), + target_compatible_with = kwargs.get("target_compatible_with", []), + ) + + _py_link_venv( + _py_venv_binary, + name = "{}_static".format(name), + srcs = srcs, + data = data, + deps = deps, + imports = kwargs.get("imports"), + tags = ["manual"], + testonly = kwargs.get("testonly", False), + target_compatible_with = kwargs.get("target_compatible_with", []), + ) + +py_venv_link = py_venv py_binary_rule = _py_binary py_test_rule = _py_test @@ -70,15 +104,12 @@ def _py_binary_or_test(name, rule, srcs, main, data = [], deps = [], **kwargs): **kwargs ) - _py_venv_link( - name = "{}.venv".format(name), + py_venv( + name = name + ".venv", srcs = srcs, data = data, deps = deps, - imports = kwargs.get("imports"), - tags = ["manual"], - testonly = kwargs.get("testonly", False), - target_compatible_with = kwargs.get("target_compatible_with", []), + **kwargs, ) def py_binary(name, srcs = [], main = None, **kwargs): diff --git a/py/private/link/BUILD.bazel b/py/private/link/BUILD.bazel new file mode 100644 index 00000000..909be7ed --- /dev/null +++ b/py/private/link/BUILD.bazel @@ -0,0 +1,41 @@ +load("@bazel_lib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["link.py"]) + +bzl_library( + name = "link", + srcs = [ + "defs.bzl" + ], + deps = [ + "@bazel_skylib//lib:sets", + ] +) + +string_flag( + name = "venv_strategy", + build_setting_default = "dynamic", + values = [ + "dynamic", + "static", + ], + visibility = ["//visibility:public"], +) + + +config_setting( + name = "static_venvs", + flag_values = { + ":venv_strategy": "static", + } +) + +config_setting( + name = "dynamic_venvs", + flag_values = { + ":venv_strategy": "dynamic", + } +) diff --git a/py/private/link/defs.bzl b/py/private/link/defs.bzl new file mode 100644 index 00000000..7b629141 --- /dev/null +++ b/py/private/link/defs.bzl @@ -0,0 +1,46 @@ +load("@bazel_skylib//lib:sets.bzl", "sets") + +def py_link_venv( + binary_rule, + name, + srcs, + args = [], + venv_name = None, + venv_dest = None, + **kwargs): + """ + Build a Python virtual environment and produce a script to link it into the + user's directory of choice. + + Args: + binary_rule (rule): A py_binary-alike rule to employ. Must build a "venv". + + venv_name (str): A name to use for venv's link. + + venv_dest (str): A path (relative to the repo + root/$BUILD_WORKING_DIRECTORY) where the link will be created. + + srcs (list): srcs for the underlying binary. + + args (list): args for the underlying binary. + + **kwargs (dict): Delegate args for the underlying binary rule. + + """ + + # Note that the binary is already wrapped with debug + link_script = str(Label("//py/private/link:link.py")) + + if venv_name != None: + args = ["--name=" + venv_name] + args + + if venv_dest != None: + args = ["--dest=" + venv_dest] + args + + binary_rule( + name = name, + args = args, + main = link_script, + srcs = sets.to_list(sets.make(srcs + [link_script])), + **kwargs + ) diff --git a/py/private/py_venv/link.py b/py/private/link/link.py similarity index 97% rename from py/private/py_venv/link.py rename to py/private/link/link.py index 9b9cbbca..99123f17 100644 --- a/py/private/py_venv/link.py +++ b/py/private/link/link.py @@ -21,7 +21,6 @@ def munge_venv_name(target_package, virtualenv_name): if __name__ == "__main__": virtualenv_home = os.path.normpath(os.environ["VIRTUAL_ENV"]) virtualenv_name = os.path.basename(virtualenv_home) - runfiles_dir = os.path.normpath(os.environ["RUNFILES_DIR"]) builddir = os.path.normpath(os.environ["BUILD_WORKING_DIRECTORY"]) target_package, target_name = os.environ["BAZEL_TARGET"].split("//", 1)[1].split(":") diff --git a/py/private/py_venv/defs.bzl b/py/private/py_venv/defs.bzl index 272b0967..aa4ea366 100644 --- a/py/private/py_venv/defs.bzl +++ b/py/private/py_venv/defs.bzl @@ -1,8 +1,7 @@ """Implementation for the py_binary and py_test rules.""" -load(":py_venv.bzl", _py_venv = "py_venv", _py_venv_binary = "py_venv_binary", _py_venv_link = "py_venv_link", _py_venv_test = "py_venv_test") +load(":py_venv.bzl", _py_venv = "py_venv", _py_venv_binary = "py_venv_binary", _py_venv_test = "py_venv_test") py_venv = _py_venv -py_venv_link = _py_venv_link py_venv_binary = _py_venv_binary py_venv_test = _py_venv_test diff --git a/py/private/py_venv/py_venv.bzl b/py/private/py_venv/py_venv.bzl index 0f3788da..5d9ea722 100644 --- a/py/private/py_venv/py_venv.bzl +++ b/py/private/py_venv/py_venv.bzl @@ -430,19 +430,3 @@ _py_venv_test = rule( py_venv = _wrap_with_debug(_py_venv) py_venv_binary = _wrap_with_debug(_py_venv_binary) py_venv_test = _wrap_with_debug(_py_venv_test) - -def py_venv_link(venv_name = None, srcs = [], **kwargs): - """Build a Python virtual environment and produce a script to link it into the build directory.""" - - # Note that the binary is already wrapped with debug - link_script = str(Label("//py/private/py_venv:link.py")) - kwargs["debug"] = select({ - Label(":debug_venv_setting"): True, - "//conditions:default": False, - }) - py_venv_binary( - args = [] + (["--name=" + venv_name] if venv_name else []), - main = link_script, - srcs = srcs + [link_script], - **kwargs - ) diff --git a/py/settings/BUILD.bazel b/py/settings/BUILD.bazel new file mode 100644 index 00000000..fe614b7e --- /dev/null +++ b/py/settings/BUILD.bazel @@ -0,0 +1,21 @@ +load("@aspect_bazel_lib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") + +# For Bazel 6.x compatibility, since +# PyRuntimeInfo shipped only with Bazel 7 +# Users can set, e.g. --@aspect_rules_py//py:interpreter_version=3.9.18 +alias( + name = "interpreter_version", + actual = "@rules_python//python/config_settings:python_version", + visibility = ["//visibility:public"], +) + +string_flag( + name = "venv_strategy", + build_setting_default = "dynamic", + values = [ + "dynamic", + "static", + ], + visibility = ["//visibility:public"], +) diff --git a/py/unstable/defs.bzl b/py/unstable/defs.bzl index 497ddf85..61748b96 100644 --- a/py/unstable/defs.bzl +++ b/py/unstable/defs.bzl @@ -5,9 +5,8 @@ Unstable rules and preview machinery. No promises are made about compatibility across releases. """ -load("//py/private/py_venv:defs.bzl", _bin = "py_venv_binary", _link = "py_venv_link", _test = "py_venv_test", _venv = "py_venv") +load("//py/private/py_venv:defs.bzl", _bin = "py_venv_binary", _test = "py_venv_test", _venv = "py_venv") py_venv = _venv -py_venv_link = _link py_venv_binary = _bin py_venv_test = _test From b8182a88e77d27c8f082b2e827e5a81dfe1a1e80 Mon Sep 17 00:00:00 2001 From: "aspect-marvin[bot]" Date: Wed, 12 Nov 2025 16:58:46 +0000 Subject: [PATCH 3/6] Pre-commit changes --- py/BUILD.bazel | 5 ++--- py/defs.bzl | 8 ++++---- py/private/link/BUILD.bazel | 9 ++++----- py/private/link/defs.bzl | 20 ++++++++++---------- py/settings/BUILD.bazel | 1 - 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/py/BUILD.bazel b/py/BUILD.bazel index e3d46776..f0c38798 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -1,11 +1,10 @@ load("@aspect_bazel_lib//:bzl_library.bzl", "bzl_library") -load("@bazel_skylib//rules:common_settings.bzl", "string_flag") alias( name = "interpreter_version", actual = "//py/settings:interpreter_version", - visibility = ["//visibility:public"], deprecation = "Please prefer py/settings:interpreter_version", + visibility = ["//visibility:public"], ) bzl_library( @@ -33,8 +32,8 @@ bzl_library( "//py/private:py_unpacked_wheel", "//py/private:py_wheel", "//py/private:virtual", - "//py/private/py_venv", "//py/private/link", + "//py/private/py_venv", "@aspect_bazel_lib//lib:utils", ], ) diff --git a/py/defs.bzl b/py/defs.bzl index 5ac019f5..65f4f3dc 100644 --- a/py/defs.bzl +++ b/py/defs.bzl @@ -42,8 +42,8 @@ load("//py/private:py_pex_binary.bzl", _py_pex_binary = "py_pex_binary") load("//py/private:py_pytest_main.bzl", _py_pytest_main = "py_pytest_main") load("//py/private:py_unpacked_wheel.bzl", _py_unpacked_wheel = "py_unpacked_wheel") load("//py/private:virtual.bzl", _resolutions = "resolutions") -load("//py/private/py_venv:defs.bzl", _py_venv_binary = "py_venv_binary") load("//py/private/link:defs.bzl", _py_link_venv = "py_link_venv") +load("//py/private/py_venv:defs.bzl", _py_venv_binary = "py_venv_binary") py_pex_binary = _py_pex_binary py_pytest_main = _py_pytest_main @@ -58,7 +58,7 @@ def py_venv(name, srcs = [], data = [], deps = [], imports = None, testonly = Fa }), tags = ["manual"], ) - + _py_link_venv( _py_binary, name = "{}_dynamic".format(name), @@ -70,7 +70,7 @@ def py_venv(name, srcs = [], data = [], deps = [], imports = None, testonly = Fa testonly = kwargs.get("testonly", False), target_compatible_with = kwargs.get("target_compatible_with", []), ) - + _py_link_venv( _py_venv_binary, name = "{}_static".format(name), @@ -109,7 +109,7 @@ def _py_binary_or_test(name, rule, srcs, main, data = [], deps = [], **kwargs): srcs = srcs, data = data, deps = deps, - **kwargs, + **kwargs ) def py_binary(name, srcs = [], main = None, **kwargs): diff --git a/py/private/link/BUILD.bazel b/py/private/link/BUILD.bazel index 909be7ed..af533407 100644 --- a/py/private/link/BUILD.bazel +++ b/py/private/link/BUILD.bazel @@ -8,11 +8,11 @@ exports_files(["link.py"]) bzl_library( name = "link", srcs = [ - "defs.bzl" + "defs.bzl", ], deps = [ "@bazel_skylib//lib:sets", - ] + ], ) string_flag( @@ -25,17 +25,16 @@ string_flag( visibility = ["//visibility:public"], ) - config_setting( name = "static_venvs", flag_values = { ":venv_strategy": "static", - } + }, ) config_setting( name = "dynamic_venvs", flag_values = { ":venv_strategy": "dynamic", - } + }, ) diff --git a/py/private/link/defs.bzl b/py/private/link/defs.bzl index 7b629141..801c6057 100644 --- a/py/private/link/defs.bzl +++ b/py/private/link/defs.bzl @@ -1,22 +1,22 @@ load("@bazel_skylib//lib:sets.bzl", "sets") def py_link_venv( - binary_rule, - name, - srcs, - args = [], - venv_name = None, - venv_dest = None, - **kwargs): + binary_rule, + name, + srcs, + args = [], + venv_name = None, + venv_dest = None, + **kwargs): """ Build a Python virtual environment and produce a script to link it into the user's directory of choice. Args: binary_rule (rule): A py_binary-alike rule to employ. Must build a "venv". - + venv_name (str): A name to use for venv's link. - + venv_dest (str): A path (relative to the repo root/$BUILD_WORKING_DIRECTORY) where the link will be created. @@ -36,7 +36,7 @@ def py_link_venv( if venv_dest != None: args = ["--dest=" + venv_dest] + args - + binary_rule( name = name, args = args, diff --git a/py/settings/BUILD.bazel b/py/settings/BUILD.bazel index fe614b7e..c5ebff38 100644 --- a/py/settings/BUILD.bazel +++ b/py/settings/BUILD.bazel @@ -1,4 +1,3 @@ -load("@aspect_bazel_lib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "string_flag") # For Bazel 6.x compatibility, since From 43747783d3723fdd94fa3f93d3983e744c04b70f Mon Sep 17 00:00:00 2001 From: "Reid D. McKenzie" Date: Thu, 13 Nov 2025 10:17:49 -0700 Subject: [PATCH 4/6] [NO TESTS] WIP --- py/private/py_venv/BUILD.bazel | 11 ----------- py/tests/venv-link/BUILD.bazel | 11 +++++++++++ py/{private/py_venv => tests/venv-link}/test_link.py | 0 3 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 py/tests/venv-link/BUILD.bazel rename py/{private/py_venv => tests/venv-link}/test_link.py (100%) diff --git a/py/private/py_venv/BUILD.bazel b/py/private/py_venv/BUILD.bazel index d2e5576a..234bb8c4 100644 --- a/py/private/py_venv/BUILD.bazel +++ b/py/private/py_venv/BUILD.bazel @@ -6,7 +6,6 @@ package(default_visibility = ["//py:__subpackages__"]) exports_files([ "entrypoint.tmpl.sh", - "link.py", ]) bool_flag( @@ -59,16 +58,6 @@ bzl_library( ], ) -py_venv_test( - name = "test_link", - srcs = [ - "link.py", - "test_link.py", - ], - imports = ["."], - main = "test_link.py", -) - bzl_library( name = "defs", srcs = ["defs.bzl"], diff --git a/py/tests/venv-link/BUILD.bazel b/py/tests/venv-link/BUILD.bazel new file mode 100644 index 00000000..74de2e9d --- /dev/null +++ b/py/tests/venv-link/BUILD.bazel @@ -0,0 +1,11 @@ +load("//py/private/py_venv:defs.bzl", "py_venv_binary") + +py_venv_test( + name = "test_link", + srcs = [ + "link.py", + "test_link.py", + ], + imports = ["."], + main = "test_link.py", +) diff --git a/py/private/py_venv/test_link.py b/py/tests/venv-link/test_link.py similarity index 100% rename from py/private/py_venv/test_link.py rename to py/tests/venv-link/test_link.py From a1bec3592bc64286719823e061434c2a695fe99d Mon Sep 17 00:00:00 2001 From: "Reid D. McKenzie" Date: Thu, 13 Nov 2025 11:13:58 -0700 Subject: [PATCH 5/6] [NO TESTS] WIP --- py/tests/venv-link/BUILD.bazel | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/tests/venv-link/BUILD.bazel b/py/tests/venv-link/BUILD.bazel index 74de2e9d..24eb9ca7 100644 --- a/py/tests/venv-link/BUILD.bazel +++ b/py/tests/venv-link/BUILD.bazel @@ -1,11 +1,11 @@ -load("//py/private/py_venv:defs.bzl", "py_venv_binary") +load("//py/private/py_venv:defs.bzl", "py_venv_test") py_venv_test( name = "test_link", srcs = [ - "link.py", + "//py/private/link:link.py", "test_link.py", ], - imports = ["."], + imports = ["../../private/link/"], main = "test_link.py", ) From 04f3c29b83ae0109c2a32a0216627f524f4b6a70 Mon Sep 17 00:00:00 2001 From: "aspect-marvin[bot]" Date: Thu, 13 Nov 2025 18:29:55 +0000 Subject: [PATCH 6/6] Pre-commit changes --- py/private/py_venv/BUILD.bazel | 1 - py/tests/venv-link/BUILD.bazel | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/py/private/py_venv/BUILD.bazel b/py/private/py_venv/BUILD.bazel index 234bb8c4..fb93cfc1 100644 --- a/py/private/py_venv/BUILD.bazel +++ b/py/private/py_venv/BUILD.bazel @@ -1,6 +1,5 @@ load("@bazel_lib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") -load(":defs.bzl", "py_venv_test") package(default_visibility = ["//py:__subpackages__"]) diff --git a/py/tests/venv-link/BUILD.bazel b/py/tests/venv-link/BUILD.bazel index 24eb9ca7..3a0e1e6e 100644 --- a/py/tests/venv-link/BUILD.bazel +++ b/py/tests/venv-link/BUILD.bazel @@ -3,8 +3,8 @@ load("//py/private/py_venv:defs.bzl", "py_venv_test") py_venv_test( name = "test_link", srcs = [ - "//py/private/link:link.py", "test_link.py", + "//py/private/link:link.py", ], imports = ["../../private/link/"], main = "test_link.py",