From 38bdaacfa4bee6404e3be78fa202cbe79120bef6 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 14 Sep 2025 23:15:49 -0700 Subject: [PATCH 1/2] basic impl --- python/private/runtime_env_toolchain.bzl | 13 ++--- .../runtime_env_toolchain_interpreter.ps1 | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 python/private/runtime_env_toolchain_interpreter.ps1 diff --git a/python/private/runtime_env_toolchain.bzl b/python/private/runtime_env_toolchain.bzl index 1956ad5e95..f3cb9c1cc5 100644 --- a/python/private/runtime_env_toolchain.bzl +++ b/python/private/runtime_env_toolchain.bzl @@ -54,12 +54,9 @@ def define_runtime_env_toolchain(name): supports_build_time_venv = supports_build_time_venv, ) - # This is a dummy runtime whose interpreter_path triggers the native rule - # logic to use the legacy behavior on Windows. - # TODO(#7844): Remove this target. py_runtime( - name = "_magic_sentinel_runtime", - interpreter_path = "/_magic_pyruntime_sentinel_do_not_use", + name = "_runtime_env_py3_runtime_windows", + interpreter = "//python/private:runtime_env_toolchain_interpreter.ps1", python_version = "PY3", visibility = ["//visibility:private"], tags = ["manual"], @@ -69,11 +66,7 @@ def define_runtime_env_toolchain(name): py_runtime_pair( name = "_runtime_env_py_runtime_pair", py3_runtime = select({ - # If we're on windows, inject the sentinel to tell native rule logic - # that we attempted to use the runtime_env toolchain and need to - # switch back to legacy behavior. - # TODO(#7844): Remove this hack. - "@platforms//os:windows": ":_magic_sentinel_runtime", + "@platforms//os:windows": ":_runtime_env_py3_runtime_windows", "//conditions:default": ":_runtime_env_py3_runtime", }), visibility = ["//visibility:public"], diff --git a/python/private/runtime_env_toolchain_interpreter.ps1 b/python/private/runtime_env_toolchain_interpreter.ps1 new file mode 100644 index 0000000000..d3910fc177 --- /dev/null +++ b/python/private/runtime_env_toolchain_interpreter.ps1 @@ -0,0 +1,51 @@ +# PowerShell equivalent of runtime_env_toolchain_interpreter.sh + +$ErrorActionPreference = "Stop" + +function Die { + param([string]$message) + $header = "Error occurred while attempting to use the deprecated Python " ` + + "toolchain `n(@rules_python//python/runtime_env_toolchain:all)." + Write-Error "$header`n$message" + exit 1 +} + +# Try the "python3" command name first, then fall back on "python". +$pythonBin = Get-Command python3 -ErrorAction SilentlyContinue +if ($null -eq $pythonBin) { + $pythonBin = Get-Command python -ErrorAction SilentlyContinue +} + +if ($null -eq $pythonBin) { + Die "Neither 'python3' nor 'python' were found on the target platform's " ` + + "PATH, which is:`n`n$($env:PATH)`n`nPlease ensure an interpreter " ` + + "is available on this platform (and marked executable), or else " ` + + "register an appropriate Python toolchain as per the " ` + + "documentation for py_runtime_pair " ` + + "(https://github.com/bazel-contrib/rules_python/blob/master/" ` + + "docs/python.md#py_runtime_pair)." +} + +# Because this is a wrapper script that invokes Python, it prevents Python +# from detecting virtualenvs like normal (i.e. using the venv symlink to +# find the real interpreter). To work around this, we have to manually +# detect the venv, then trick the interpreter into understanding we're in a +# virtual env. +$selfDir = $PSScriptRoot +$venvPath = Join-Path $selfDir "pyvenv.cfg" +$venvParentPath = Join-Path $selfDir "..\pyvenv.cfg" + +if ((Test-Path $venvPath) -or (Test-Path $venvParentPath)) { + $venvBin = $MyInvocation.MyCommand.Path + if (-not (Test-Path $pythonBin.Source)) { + Die "ERROR: Python interpreter does not exist: $($pythonBin.Source)" + } + # PYTHONEXECUTABLE is also used because switching argv0 doesn't fully + # trick the pyenv wrappers. + # NOTE: The PYTHONEXECUTABLE envvar only works for non-Mac starting in + # Python 3.11 + $env:PYTHONEXECUTABLE = $venvBin +} +# NOTE: Windows doesn't have an exec equivalent. The call operator (&) +# creates a sub-process, which is the closest equivalent. +& $pythonBin.Source $args From 71b628a62236cf39097ae247c4a0a64785bbd539 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Mon, 15 Sep 2025 00:03:25 -0700 Subject: [PATCH 2/2] cleanup --- .../runtime_env_toolchain_interpreter.ps1 | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/python/private/runtime_env_toolchain_interpreter.ps1 b/python/private/runtime_env_toolchain_interpreter.ps1 index d3910fc177..de6ffca425 100644 --- a/python/private/runtime_env_toolchain_interpreter.ps1 +++ b/python/private/runtime_env_toolchain_interpreter.ps1 @@ -4,26 +4,26 @@ $ErrorActionPreference = "Stop" function Die { param([string]$message) - $header = "Error occurred while attempting to use the deprecated Python " ` - + "toolchain `n(@rules_python//python/runtime_env_toolchain:all)." + $header = ("Error occurred while attempting to use the deprecated Python " + + "toolchain `n(@rules_python//python/runtime_env_toolchain:all).") Write-Error "$header`n$message" exit 1 } # Try the "python3" command name first, then fall back on "python". $pythonBin = Get-Command python3 -ErrorAction SilentlyContinue -if ($null -eq $pythonBin) { +if (-not $pythonBin) { $pythonBin = Get-Command python -ErrorAction SilentlyContinue } -if ($null -eq $pythonBin) { - Die "Neither 'python3' nor 'python' were found on the target platform's " ` - + "PATH, which is:`n`n$($env:PATH)`n`nPlease ensure an interpreter " ` - + "is available on this platform (and marked executable), or else " ` - + "register an appropriate Python toolchain as per the " ` - + "documentation for py_runtime_pair " ` - + "(https://github.com/bazel-contrib/rules_python/blob/master/" ` - + "docs/python.md#py_runtime_pair)." +if (-not $pythonBin) { + Die ("Neither 'python3' nor 'python' were found on the target platform's " + + "PATH, which is:`n`n$($env:PATH)`n`nPlease ensure an interpreter " + + "is available on this platform (and marked executable), or else " + + "register an appropriate Python toolchain as per the " + + "documentation for py_runtime_pair " + + "(https://github.com/bazel-contrib/rules_python/blob/master/" + + "docs/python.md#py_runtime_pair).") } # Because this is a wrapper script that invokes Python, it prevents Python