From a4f80ce23f2bba93244c577b571b08b345c3d95e Mon Sep 17 00:00:00 2001 From: Romwierz Date: Mon, 7 Sep 2026 18:10:43 +0200 Subject: [PATCH 01/12] pyenv-exec: add option to modify python runtime for the called executable The only variables modified are $PYTHONHOME and $LD_LIBRARY_PATH which will allow the executable to use the shared library of the Python version which is selected with pyenv. --- libexec/pyenv-exec | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index d0f6d071..6477d7f9 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -2,7 +2,9 @@ # # Summary: Run an executable with the selected Python version # -# Usage: pyenv exec [arg1 arg2...] +# Usage: pyenv exec [-E|--environment] [arg1 arg2...] +# +# -E Modify Python runtime environment, such as $PYTHONHOME, for the called executable. # # Runs an executable by first preparing PATH so that the selected Python # version's `bin' directory is at the front. @@ -18,9 +20,16 @@ set -e # Provide pyenv completions if [ "$1" = "--complete" ]; then + echo --environment exec pyenv-shims --short fi +unset MODIFY_ENV +if [ "$1" = "-E" ] || [ "$1" = "--environment" ]; then + MODIFY_ENV=true + shift +fi + PYENV_VERSION="$(pyenv-version-name -f)" PYENV_COMMAND="$1" @@ -54,4 +63,8 @@ if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then # Only add to $PATH for non-system version. export PATH="${PYENV_BIN_PATH}:${PATH}" fi +if [ -n "$MODIFY_ENV" ]; then + export PYTHONHOME="$(pyenv-prefix)" + export LD_LIBRARY_PATH="${PYTHONHOME}/lib:${LD_LIBRARY_PATH}" +fi exec "$PYENV_COMMAND_PATH" "$@" From 63548e129f111d999fc96660b59250bc94a03e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= <103243820+Romwierz@users.noreply.github.com> Date: Mon, 7 Sep 2026 19:25:58 +0200 Subject: [PATCH 02/12] fix libexec/pyenv-exec Make sure the $LD_LIBRARY_PATH does not have a trailing colon. Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- libexec/pyenv-exec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index 6477d7f9..f77227b2 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -65,6 +65,6 @@ if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then fi if [ -n "$MODIFY_ENV" ]; then export PYTHONHOME="$(pyenv-prefix)" - export LD_LIBRARY_PATH="${PYTHONHOME}/lib:${LD_LIBRARY_PATH}" + export LD_LIBRARY_PATH="${PYTHONHOME}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" fi exec "$PYENV_COMMAND_PATH" "$@" From 4113b2d9f78ab2cb133378abbbe82226aaf47d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= <103243820+Romwierz@users.noreply.github.com> Date: Tue, 8 Sep 2026 10:49:16 +0200 Subject: [PATCH 03/12] add warning about setting envvars Co-authored-by: native-api --- libexec/pyenv-exec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index f77227b2..6380dfc9 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -4,7 +4,8 @@ # # Usage: pyenv exec [-E|--environment] [arg1 arg2...] # -# -E Modify Python runtime environment, such as $PYTHONHOME, for the called executable. +# -E Set PYTHONHOME and LD_LIBRARY_PATH envvars for the running command. This allows to run programs that embed Python without using rpath or exact library path. +# WARNING! For the running command and its child processes, this will break linkage for programs that expect to be linked to system libpython! # # Runs an executable by first preparing PATH so that the selected Python # version's `bin' directory is at the front. From 2eb849102ae0256ad6b40a272db383faf4071208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= <103243820+Romwierz@users.noreply.github.com> Date: Tue, 8 Sep 2026 11:12:38 +0200 Subject: [PATCH 04/12] fix lengths of lines Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- libexec/pyenv-exec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index 6380dfc9..7b08b88e 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -4,8 +4,11 @@ # # Usage: pyenv exec [-E|--environment] [arg1 arg2...] # -# -E Set PYTHONHOME and LD_LIBRARY_PATH envvars for the running command. This allows to run programs that embed Python without using rpath or exact library path. -# WARNING! For the running command and its child processes, this will break linkage for programs that expect to be linked to system libpython! +# -E Set PYTHONHOME and LD_LIBRARY_PATH envvars for the running command. +# This allows to run programs that embed Python without using rpath or +# exact library path. +# WARNING! For the running command and its child processes, this will +# break linkage for programs that expect to be linked to system libpython! # # Runs an executable by first preparing PATH so that the selected Python # version's `bin' directory is at the front. From fbd0abd3f7a8d386e9213d727bfff0b18e6ab01d Mon Sep 17 00:00:00 2001 From: Romwierz Date: Tue, 8 Sep 2026 12:05:04 +0200 Subject: [PATCH 05/12] check if multiple Python versions are selected and use the first one --- libexec/pyenv-exec | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index 7b08b88e..6117d700 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -68,7 +68,18 @@ if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then export PATH="${PYENV_BIN_PATH}:${PATH}" fi if [ -n "$MODIFY_ENV" ]; then - export PYTHONHOME="$(pyenv-prefix)" + # Check if multiple Python versions are selected + VERSIONS=$(pyenv-prefix) + if [[ "$VERSIONS" == *:* ]]; then + echo 'Warning: multiple Python versions are selected' + VERSION="${VERSIONS%%:*}" + echo "Using the first one available (${VERSION##*/})" + else + VERSION="$VERSIONS" + fi + + # Assign the correct version of PYTHONHOME + export PYTHONHOME="$VERSION" export LD_LIBRARY_PATH="${PYTHONHOME}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" fi exec "$PYENV_COMMAND_PATH" "$@" From b8c7b387bffd54243a7c2471477263286711a6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= <103243820+Romwierz@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:15:23 +0200 Subject: [PATCH 06/12] send diagnostics to stderr Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- libexec/pyenv-exec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index 6117d700..bb116a75 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -71,9 +71,9 @@ if [ -n "$MODIFY_ENV" ]; then # Check if multiple Python versions are selected VERSIONS=$(pyenv-prefix) if [[ "$VERSIONS" == *:* ]]; then - echo 'Warning: multiple Python versions are selected' + echo 'Warning: multiple Python versions are selected' >&2 VERSION="${VERSIONS%%:*}" - echo "Using the first one available (${VERSION##*/})" + echo "Using the first one available (${VERSION##*/})" >&2 else VERSION="$VERSIONS" fi From ac101f355d6e2ef20a0b788d665fece111d41672 Mon Sep 17 00:00:00 2001 From: Romwierz Date: Tue, 8 Sep 2026 12:18:00 +0200 Subject: [PATCH 07/12] modify test's asserted output --- test/exec.bats | 1 + 1 file changed, 1 insertion(+) diff --git a/test/exec.bats b/test/exec.bats index ff49912b..e603c3f8 100644 --- a/test/exec.bats +++ b/test/exec.bats @@ -34,6 +34,7 @@ EOF assert_success assert_output < Date: Wed, 9 Sep 2026 10:21:48 +0200 Subject: [PATCH 08/12] change the flag name --- libexec/pyenv-exec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index bb116a75..be5b09dd 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -2,9 +2,9 @@ # # Summary: Run an executable with the selected Python version # -# Usage: pyenv exec [-E|--environment] [arg1 arg2...] +# Usage: pyenv exec [-N|--environment] [arg1 arg2...] # -# -E Set PYTHONHOME and LD_LIBRARY_PATH envvars for the running command. +# -N Set PYTHONHOME and LD_LIBRARY_PATH envvars for the running command. # This allows to run programs that embed Python without using rpath or # exact library path. # WARNING! For the running command and its child processes, this will @@ -29,7 +29,7 @@ if [ "$1" = "--complete" ]; then fi unset MODIFY_ENV -if [ "$1" = "-E" ] || [ "$1" = "--environment" ]; then +if [ "$1" = "-N" ] || [ "$1" = "--environment" ]; then MODIFY_ENV=true shift fi From b64372d93975d61bff1e7a64470fdc70bd8db73a Mon Sep 17 00:00:00 2001 From: Romwierz Date: Wed, 9 Sep 2026 10:41:50 +0200 Subject: [PATCH 09/12] make the option linux only --- libexec/pyenv-exec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index be5b09dd..ac664df6 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -9,6 +9,7 @@ # exact library path. # WARNING! For the running command and its child processes, this will # break linkage for programs that expect to be linked to system libpython! +# This option is Linux only. # # Runs an executable by first preparing PATH so that the selected Python # version's `bin' directory is at the front. @@ -67,7 +68,7 @@ if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then # Only add to $PATH for non-system version. export PATH="${PYENV_BIN_PATH}:${PATH}" fi -if [ -n "$MODIFY_ENV" ]; then +if [ -n "$MODIFY_ENV" ] && [ "$(uname -s)" = Linux ]; then # Check if multiple Python versions are selected VERSIONS=$(pyenv-prefix) if [[ "$VERSIONS" == *:* ]]; then From d7ec016b32d77dd7554c65c28d55ca898e7d06d3 Mon Sep 17 00:00:00 2001 From: Romwierz Date: Wed, 9 Sep 2026 10:53:02 +0200 Subject: [PATCH 10/12] reject running the command on non-linux system --- libexec/pyenv-exec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index ac664df6..a55d1a29 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -68,7 +68,12 @@ if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then # Only add to $PATH for non-system version. export PATH="${PYENV_BIN_PATH}:${PATH}" fi -if [ -n "$MODIFY_ENV" ] && [ "$(uname -s)" = Linux ]; then +if [ -n "$MODIFY_ENV" ]; then + if [ "$(uname -s)" != Linux ]; then + echo 'Error: the -N option is supported only on Linux' >&2 + exit 1 + fi + # Check if multiple Python versions are selected VERSIONS=$(pyenv-prefix) if [[ "$VERSIONS" == *:* ]]; then From 3e0ed2d1a075a7ca242a323a2a64e287fc818dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= <103243820+Romwierz@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:00:06 +0200 Subject: [PATCH 11/12] change error message Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- libexec/pyenv-exec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index a55d1a29..f2bc2449 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -70,7 +70,7 @@ if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then fi if [ -n "$MODIFY_ENV" ]; then if [ "$(uname -s)" != Linux ]; then - echo 'Error: the -N option is supported only on Linux' >&2 + echo 'Error: the --environment option is supported only on Linux' >&2 exit 1 fi From fa03780a37386e3fb102c9d25830cd890c5db96d Mon Sep 17 00:00:00 2001 From: Romwierz Date: Wed, 9 Sep 2026 12:17:54 +0200 Subject: [PATCH 12/12] tests: add 'fails on non-Linux system' --- test/exec.bats | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/exec.bats b/test/exec.bats index e603c3f8..209d9cf4 100644 --- a/test/exec.bats +++ b/test/exec.bats @@ -140,3 +140,21 @@ $envvarname=/unusual/shim/location:/another/shim/location _PYENV_SHIM_PATH= ! } + +@test "fails on non-Linux system" { + # Make sure to use the system version of Python + mkdir -p "$PYENV_TEST_DIR" + cd "$PYENV_TEST_DIR" + echo '' > .python-version + + run uname -s + if [ "$output" != Linux ]; then + run pyenv-exec -N env + assert_failure + assert_output 'Error: the --environment option is supported only on Linux' + else + run pyenv-exec -N env + echo "$status" + assert_success + fi +}