Compare commits

..

No commits in common. "master" and "v1.3.0" have entirely different histories.

10 changed files with 207 additions and 320 deletions

View file

@ -6,12 +6,11 @@ jobs:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- ubuntu-24.04
- macos-14
- macos-15
- ubuntu-22.04
- macos-15-intel
- macos-26
- macos-15
- macos-14
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2

View file

@ -1,9 +1,5 @@
## Version History
## v1.4.0
* Fix POSIX sh (dash) compatibility in pyenv-virtualenv-init by @chrisolof in https://github.com/pyenv/pyenv-virtualenv/pull/526
* Improve performance and output of `pyenv virtualenvs` by @samdoran in https://github.com/pyenv/pyenv-virtualenv/pull/502
## v1.3.0
* CI: cleanup by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/521
* CI: tests: use Bats 1.10; support concurrent, out-of-order and multiple-times execution of stub commands; fix race condition between concurrent stubs by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/520

View file

@ -13,7 +13,7 @@
# -u/--upgrade Imply --force
#
PYENV_VIRTUALENV_VERSION="1.4.0"
PYENV_VIRTUALENV_VERSION="1.3.0"
set -e
[ -n "$PYENV_DEBUG" ] && set -x
@ -24,7 +24,7 @@ fi
# Provide pyenv completions
if [ "$1" = "--complete" ]; then
exec pyenv-versions --bare --skip-envs
exec pyenv-versions --bare
fi
unset PIP_REQUIRE_VENV

View file

@ -120,13 +120,22 @@ esac
case "$shell" in
fish )
cat <<EOS
if [ -n "$_has_version_hooks" ]; then
cat <<EOS
function _pyenv_virtualenv_hook --on-event fish_prompt;
set -l ret \$status
if [ -n "\$VIRTUAL_ENV" ]
pyenv activate --quiet; or pyenv deactivate --quiet; or true
else
pyenv activate --quiet; or true
end
return \$ret
end
EOS
if [ -z "$_has_version_hooks" ]; then
else
cat <<EOS
function _pyenv_virtualenv_hook --on-event fish_prompt;
set -l ret \$status
if test "\$PYENV_VERSION" = "\$_PYENV_VH_VERSION" \\
-a "\$VIRTUAL_ENV" = "\$_PYENV_VH_VENV"
if test -n "\$PYENV_VERSION"
@ -137,19 +146,11 @@ EOS
return \$ret
end
end
EOS
fi
cat <<EOS
if [ -n "\$VIRTUAL_ENV" ]
pyenv activate --quiet; or pyenv deactivate --quiet; or true
else
pyenv activate --quiet; or true
end
EOS
if [ -z "$_has_version_hooks" ]; then
cat <<EOS
set -g _PYENV_VH_PWD "\$PWD"
set -g _PYENV_VH_VERSION "\$PYENV_VERSION"
set -g _PYENV_VH_VENV "\$VIRTUAL_ENV"
@ -174,23 +175,39 @@ EOS
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$PYENV_ROOT/version"
end
set -g _PYENV_VH_MTIMES (stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)
EOS
fi
cat <<EOS
return \$ret
end
EOS
fi
;;
ksh )
cat <<EOS
function _pyenv_virtualenv_hook() {
EOS
;;
bash|zsh )
* )
cat <<EOS
_pyenv_virtualenv_hook() {
local ret=\$?
EOS
;;
esac
if [ -z "$_has_version_hooks" ]; then
if [[ "$shell" != "fish" ]]; then
if [ -n "$_has_version_hooks" ]; then
cat <<EOS
local ret=\$?
if [ -n "\${VIRTUAL_ENV-}" ]; then
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
else
eval "\$(pyenv sh-activate --quiet || true)" || true
fi
return \$ret
};
EOS
else
cat <<EOS
local ret=\$?
# Cache: env vars checked once, path list and stat rebuilt on miss only
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
if [ -n "\${PYENV_VERSION-}" ]; then
@ -201,19 +218,11 @@ EOS
return \$ret
fi
fi
EOS
fi
cat <<EOS
if [ -n "\${VIRTUAL_ENV-}" ]; then
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
else
eval "\$(pyenv sh-activate --quiet || true)" || true
fi
EOS
if [ -z "$_has_version_hooks" ]; then
cat <<EOS
_PYENV_VH_PWD="\${PWD}"
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
@ -237,33 +246,29 @@ EOS
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
fi
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
EOS
fi
cat <<EOS
return \$ret
};
EOS
;;
esac
fi
case "$shell" in
bash )
cat <<EOS
case "$shell" in
bash )
cat <<EOS
if ! [[ "\${PROMPT_COMMAND-}" =~ _pyenv_virtualenv_hook ]]; then
PROMPT_COMMAND="_pyenv_virtualenv_hook;\${PROMPT_COMMAND-}"
fi
EOS
;;
zsh )
cat <<EOS
;;
zsh )
cat <<EOS
typeset -g -a precmd_functions
if [[ -z \$precmd_functions[(r)_pyenv_virtualenv_hook] ]]; then
precmd_functions=(_pyenv_virtualenv_hook \$precmd_functions);
fi
EOS
;;
* )
# No prompt command support or it's installed elsewhere
;;
esac
;;
* )
# FIXME: what should i do here??
;;
esac
fi

View file

@ -26,17 +26,13 @@ if [ -z "$PYENV_ROOT" ]; then
PYENV_ROOT="${HOME}/.pyenv"
fi
OLDIFS="$IFS"
IFS=:
if [ -n "$1" ]; then
# $@ is not affected by IFS
versions=("$@")
PYENV_VERSION="${versions[*]}"
versions=($@)
IFS=: PYENV_VERSION="${versions[*]}"
export PYENV_VERSION
else
versions=($(pyenv-version-name))
IFS=: versions=($(pyenv-version-name))
fi
IFS="$OLDIFS"
append_virtualenv_prefix() {
if [ -d "${VIRTUALENV_PREFIX_PATH}" ]; then
@ -53,18 +49,7 @@ for version in "${versions[@]}"; do
echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2
exit 1
fi
# In the vast majority of cases, there's a direct match and
# not spawning `pyenv-prefix' saves about half the invocation time
# with a signle argument which accumulates when called repeatedly
# (e.g. from `pyenv-virtualenvs').
# `pyenv-prefix' also does not have hooks to worry about.
# XXX: refactor the test into a shared module?
PYENV_PREFIX_PATH="${PYENV_ROOT}/versions/${version}"
if [[ ! -d "$PYENV_PREFIX_PATH" ]]; then
PYENV_PREFIX_PATH="$(pyenv-prefix "${version}")"
fi
PYENV_PREFIX_PATH="$(pyenv-prefix "${version}")"
if [ -x "${PYENV_PREFIX_PATH}/bin/python" ]; then
if [ -f "${PYENV_PREFIX_PATH}/bin/activate" ]; then
if [ -f "${PYENV_PREFIX_PATH}/bin/conda" ]; then
@ -109,7 +94,4 @@ for version in "${versions[@]}"; do
fi
done
OLDIFS="$IFS"
IFS=:
echo "${VIRTUALENV_PREFIX_PATHS[*]}"
IFS="$OLDIFS"
IFS=: echo "${VIRTUALENV_PREFIX_PATHS[*]}"

View file

@ -6,9 +6,24 @@
# List all virtualenvs found in `$PYENV_ROOT/versions/*' and its `$PYENV_ROOT/versions/envs/*'.
set -e
[[ -n $PYENV_DEBUG ]] && set -x
[ -n "$PYENV_DEBUG" ] && set -x
if [ -L "${BASH_SOURCE}" ]; then
READLINK=$(type -p greadlink readlink | head -1)
if [ -z "$READLINK" ]; then
echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
exit 1
fi
resolve_link() {
$READLINK -f "$1"
}
script_path=$(resolve_link ${BASH_SOURCE})
else
script_path=${BASH_SOURCE}
fi
if [[ -z $PYENV_ROOT ]]; then
. ${script_path%/*}/../libexec/pyenv-virtualenv-realpath
if [ -z "$PYENV_ROOT" ]; then
PYENV_ROOT="${HOME}/.pyenv"
fi
@ -32,26 +47,28 @@ done
versions_dir="${PYENV_ROOT}/versions"
if [[ ${BASH_VERSINFO[0]} -gt 3 ]]; then
declare -A current_versions
else
current_versions=()
if [ -d "$versions_dir" ]; then
versions_dir="$(realpath "$versions_dir")"
fi
if [[ -z $bare ]]; then
if [ -n "$bare" ]; then
hit_prefix=""
miss_prefix=""
current_versions=()
unset print_origin
include_system=""
else
hit_prefix="* "
miss_prefix=" "
OLDIFS="$IFS"
IFS=:
if [[ ${BASH_VERSINFO[0]} -gt 3 ]]; then
for i in $(pyenv-version-name || true); do
current_versions["$i"]="1"
done
else
read -r -a current_versions <<< "$(pyenv-version-name || true)"
fi
IFS=: current_versions=($(pyenv-version-name || true))
IFS="$OLDIFS"
print_origin="1"
include_system=""
fi
num_versions=0
exists() {
local car="$1"
local cdar
@ -65,67 +82,39 @@ exists() {
}
print_version() {
local version="${1:?}"
if [[ -n $bare ]]; then
echo "$version"
return
fi
local path="${2:?}"
if [[ -L "$path" ]]; then
version_repr="$version --> $(readlink "$path")"
if exists "$1" "${current_versions[@]}"; then
echo "${hit_prefix}${1}${print_origin+$2}"
else
version_repr="$version (created from $(pyenv-virtualenv-prefix "$version" 2>/dev/null))"
fi
if [[ ${BASH_VERSINFO[0]} -gt 3 && ${current_versions["$1"]} ]] || \
{ [[ ${BASH_VERSINFO[0]} -le 3 ]] && exists "$1" "${current_versions[@]}"; }; then
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
else
echo "${miss_prefix}${version_repr}"
echo "${miss_prefix}${1}${print_origin+$2}"
fi
num_versions=$((num_versions + 1))
}
shopt -s dotglob
shopt -s nullglob
version_dir_entries=("$versions_dir"/*)
venv_dir_entries=("$versions_dir"/*/envs/*)
if sort --version-sort </dev/null >/dev/null 2>&1; then
# system sort supports version sorting
OLDIFS="$IFS"
IFS='||'
read -r -a version_dir_entries <<< "$(
printf "%s||" "${version_dir_entries[@]}" |
sort --version-sort
)"
read -r -a venv_dir_entries <<< "$(
printf "%s||" "${venv_dir_entries[@]}" |
sort --version-sort
)"
IFS="$OLDIFS"
fi
for env_path in "${venv_dir_entries[@]}"; do
if [[ -d ${env_path} ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
done
for env_path in "${version_dir_entries[@]}"; do
if [[ -d ${env_path} ]]; then
if [[ -L ${env_path} ]]; then
if [[ -z $skip_aliases ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
# Mimics the test from pyenv-virtualenv-prefix
# XXX: refactor itto a shared module ?
elif [[ -f "${env_path}/bin/activate" ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
for path in "$versions_dir"/*; do
if [ -d "$path" ]; then
if [ -n "$skip_aliases" ] && [ -L "$path" ]; then
target="$(realpath "$path")"
[ "${target%/*/envs/*}" != "$versions_dir" ] || continue
fi
virtualenv_prefix="$(pyenv-virtualenv-prefix "${path##*/}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${path##*/}" " (created from ${virtualenv_prefix})"
fi
for venv_path in "${path}/envs/"*; do
venv="${path##*/}/envs/${venv_path##*/}"
virtualenv_prefix="$(pyenv-virtualenv-prefix "${venv}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${venv}" " (created from ${virtualenv_prefix})"
fi
done
fi
done
shopt -u dotglob
shopt -u nullglob
if [ "$num_versions" -eq 0 ] && [ -n "$include_system" ]; then
echo "Warning: no Python virtualenv detected on the system" >&2
exit 1
fi

View file

@ -9,6 +9,7 @@ setup() {
@test "display conda root" {
setup_conda "anaconda-2.3.0"
stub pyenv-version-name "echo anaconda-2.3.0"
stub pyenv-prefix "anaconda-2.3.0 : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0\""
PYENV_VERSION="anaconda-2.3.0" run pyenv-virtualenv-prefix
@ -18,12 +19,14 @@ ${PYENV_ROOT}/versions/anaconda-2.3.0
OUT
unstub pyenv-version-name
unstub pyenv-prefix
teardown_conda "anaconda-2.3.0"
}
@test "display conda env" {
setup_conda "anaconda-2.3.0" "foo"
stub pyenv-version-name "echo anaconda-2.3.0/envs/foo"
stub pyenv-prefix "anaconda-2.3.0/envs/foo : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0/envs/foo\""
PYENV_VERSION="anaconda-2.3.0/envs/foo" run pyenv-virtualenv-prefix
@ -33,5 +36,6 @@ ${PYENV_ROOT}/versions/anaconda-2.3.0/envs/foo
OUT
unstub pyenv-version-name
unstub pyenv-prefix
teardown_conda "anaconda-2.3.0" "foo"
}

View file

@ -29,18 +29,22 @@ load test_helper
rm -f "${TMP}/script.sh"
}
@test "sh-compatible instructions" {
run pyenv-virtualenv-init bash
assert [ "$status" -eq 1 ]
assert_output_contains 'eval "$(pyenv virtualenv-init -)"'
run pyenv-virtualenv-init zsh
assert [ "$status" -eq 1 ]
assert_output_contains 'eval "$(pyenv virtualenv-init -)"'
}
@test "fish instructions" {
run pyenv-virtualenv-init fish
assert [ "$status" -eq 1 ]
assert_output_contains 'status --is-interactive; and source (pyenv virtualenv-init -|psub)'
}
@test "other shells instructions" {
run pyenv-virtualenv-init some_other_sh
assert [ "$status" -eq 1 ]
assert_output_contains 'eval "$(pyenv virtualenv-init -)"'
}
@test "outputs bash-specific syntax" {
export PYENV_VIRTUALENV_ROOT="${TMP}/pyenv/plugins/pyenv-virtualenv"
run pyenv-virtualenv-init - bash
@ -50,6 +54,7 @@ export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
export PYENV_VIRTUALENV_INIT=1;
_pyenv_virtualenv_hook() {
local ret=\$?
# Cache: env vars checked once, path list and stat rebuilt on miss only
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
if [ -n "\${PYENV_VERSION-}" ]; then
@ -160,6 +165,7 @@ export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
export PYENV_VIRTUALENV_INIT=1;
_pyenv_virtualenv_hook() {
local ret=\$?
# Cache: env vars checked once, path list and stat rebuilt on miss only
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
if [ -n "\${PYENV_VERSION-}" ]; then
@ -206,13 +212,3 @@ if [[ -z \$precmd_functions[(r)_pyenv_virtualenv_hook] ]]; then
fi
EOS
}
@test "outputs other shells syntax" {
export PYENV_VIRTUALENV_ROOT="${TMP}/pyenv/plugins/pyenv-virtualenv"
run pyenv-virtualenv-init - some_other_sh
assert_success
assert_output <<EOS
export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
export PYENV_VIRTUALENV_INIT=1;
EOS
}

View file

@ -12,6 +12,10 @@ create_version() {
chmod +x "${PYENV_ROOT}/versions/$1/bin/python"
}
remove_version() {
rm -fr "${PYENV_ROOT}/versions/$1"
}
create_virtualenv() {
create_version "$1"
create_version "${2:-$1}"
@ -36,6 +40,11 @@ create_virtualenv_pypy() {
touch "${PYENV_ROOT}/versions/$1/bin/activate"
}
remove_virtualenv() {
remove_version "$1"
remove_version "${2:-$1}"
}
create_m_venv() {
create_version "$1"
create_version "${2:-$1}"
@ -43,6 +52,10 @@ create_m_venv() {
touch "${PYENV_ROOT}/versions/$1/bin/activate"
}
remove_m_venv() {
remove_version "${2:-$1}"
}
create_conda() {
create_version "$1"
create_version "${2:-$1}"
@ -53,8 +66,13 @@ create_conda() {
touch "${PYENV_ROOT}/versions/${2:-$1}/bin/activate"
}
remove_conda() {
remove_version "${2:-$1}"
}
@test "display prefix of virtualenv created by virtualenv" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_virtualenv "foo" "2.7.11"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -65,10 +83,13 @@ ${PYENV_ROOT}/versions/2.7.11
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "2.7.11"
}
@test "display prefix of virtualenv created by virtualenv (pypy)" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_virtualenv_pypy "foo" "pypy-4.0.1"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -79,10 +100,13 @@ ${PYENV_ROOT}/versions/pypy-4.0.1
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "pypy-4.0.1"
}
@test "display prefix of virtualenv created by virtualenv (jython)" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_virtualenv_jython "foo" "jython-2.7.0"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -93,10 +117,14 @@ ${PYENV_ROOT}/versions/jython-2.7.0
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "jython-2.7.0"
}
@test "display prefixes of virtualenv created by virtualenv" {
stub pyenv-version-name "echo foo:bar"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\"" \
"bar : echo \"${PYENV_ROOT}/versions/bar\""
create_virtualenv "foo" "2.7.11"
create_virtualenv "bar" "3.5.1"
@ -108,10 +136,14 @@ ${PYENV_ROOT}/versions/2.7.11:${PYENV_ROOT}/versions/3.5.1
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "2.7.11"
remove_virtualenv "bar" "3.5.1"
}
@test "display prefix of virtualenv created by venv" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_m_venv "foo" "3.3.6"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -122,10 +154,14 @@ ${PYENV_ROOT}/versions/3.3.6
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_m_venv "foo" "3.3.6"
}
@test "display prefixes of virtualenv created by venv" {
stub pyenv-version-name "echo foo:bar"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\"" \
"bar : echo \"${PYENV_ROOT}/versions/bar\""
create_m_venv "foo" "3.3.6"
create_m_venv "bar" "3.4.4"
@ -137,10 +173,14 @@ ${PYENV_ROOT}/versions/3.3.6:${PYENV_ROOT}/versions/3.4.4
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_m_venv "foo" "3.3.6"
remove_m_venv "bar" "3.4.4"
}
@test "display prefix of virtualenv created by conda" {
stub pyenv-version-name "echo miniconda3-3.16.0/envs/foo"
stub pyenv-prefix "miniconda3-3.16.0/envs/foo : echo \"${PYENV_ROOT}/versions/miniconda3-3.16.0/envs/foo\""
create_conda "miniconda3-3.16.0/envs/foo" "miniconda3-3.16.0"
PYENV_VERSION="miniconda3-3.16.0/envs/foo" run pyenv-virtualenv-prefix
@ -151,6 +191,8 @@ ${PYENV_ROOT}/versions/miniconda3-3.16.0/envs/foo
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_conda "miniconda3-3.16.0/envs/foo" "miniconda3-3.16.0"
}
@test "should fail if the version is the system" {
@ -168,6 +210,7 @@ OUT
@test "should fail if the version is not a virtualenv" {
stub pyenv-version-name "echo 3.4.4"
stub pyenv-prefix "3.4.4 : echo \"${PYENV_ROOT}/versions/3.4.4\""
create_version "3.4.4"
PYENV_VERSION="3.4.4" run pyenv-virtualenv-prefix
@ -178,10 +221,14 @@ pyenv-virtualenv: version \`3.4.4' is not a virtualenv
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_version "3.4.4"
}
@test "should fail if one of the versions is not a virtualenv" {
stub pyenv-version-name "echo venv33:3.4.4"
stub pyenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/venv33\"" \
"3.4.4 : echo \"${PYENV_ROOT}/versions/3.4.4\""
create_virtualenv "venv33" "3.3.6"
create_version "3.4.4"
@ -190,25 +237,10 @@ OUT
assert_failure
assert_output <<OUT
pyenv-virtualenv: version \`3.4.4' is not a virtualenv
OUT
unstub pyenv-version-name
}
@test "resolves a version that is not an exact match" {
stub pyenv-version-name "echo 3"
create_version "3.4.4"
stub pyenv-prefix "3 : echo \"$PYENV_ROOT/versions/3.4.4\""
run pyenv-virtualenv-prefix
assert_failure
assert_output <<OUT
pyenv-virtualenv: version \`3' is not a virtualenv
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "venv33" "3.3.6"
remove_version "3.4.4"
}

View file

@ -2,79 +2,27 @@
load test_helper
create_m_system_venv() {
# Create a mock virtual environment in the same way a venv created from
# the system Python version looks.
#
# The venv is in ${PYENV_ROOT}/versions, is not a symlink, and
# home is /usr/bin in the pyenv.cfg.
create_executable "$2" "python"
create_executable "$2" "activate"
local version="$1"
local venv="$2"
local venv_dir="${PYENV_ROOT}/versions/${venv}"
echo "home = /usr/bin" > "${venv_dir}/pyvenv.cfg"
}
create_m_venv() {
# Create a mock virtual environment from an installed (not system) Python version.
#
# The venv name is a symlink inside ${PYENV_ROOT}/versions that points to
# the real venv directory inside the Python version used to created and
# home points to the bin directory inside the venv dir.
setup_m_venv "$1/envs/$2"
local version="$1"
local venv="$2"
local venv_dir="${PYENV_ROOT}/versions/${version}/envs/${venv}"
echo "home = ${PYENV_ROOT}/versions/${version}/bin" > "${venv_dir}/pyvenv.cfg"
ln -sf "${venv_dir}" "${PYENV_ROOT}/versions/${venv}"
}
setup() {
export PYENV_ROOT="${TMP}/pyenv"
mkdir -p "${PYENV_ROOT}/versions/2.7.6"
mkdir -p "${PYENV_ROOT}/versions/3.3.3"
mkdir -p "${PYENV_ROOT}/versions/venv27"
mkdir -p "${PYENV_ROOT}/versions/venv33"
}
@test "system venv" {
stub pyenv-version-name ": echo venv314"
stub pyenv-version-origin ": echo PYENV_VERSION"
create_m_venv "3.14.3" "venv314"
create_m_system_venv "3.9.11" "system_venv"
run pyenv-virtualenvs
assert_success
assert_output <<OUT
3.14.3/envs/venv314 (created from ${PYENV_ROOT}/versions/3.14.3)
system_venv (created from /usr)
* venv314 --> ${PYENV_ROOT}/versions/3.14.3/envs/venv314 (set by PYENV_VERSION)
OUT
unstub pyenv-version-name
unstub pyenv-version-origin
}
@test "list virtual environments" {
@test "list virtual environments only" {
stub pyenv-version-name ": echo system"
stub pyenv-virtualenv-prefix "2.7.6/envs/venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\""
stub pyenv-virtualenv-prefix "3.3.3/envs/venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\""
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\""
stub pyenv-virtualenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\""
run pyenv-virtualenvs
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
OUT
unstub pyenv-version-name
@ -82,101 +30,37 @@ OUT
}
@test "list virtual environments with hit prefix" {
stub pyenv-version-name ": echo 3.3.3/envs/venv33"
stub pyenv-version-origin ": echo PYENV_VERSION"
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
stub pyenv-version-name ": echo venv33"
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"/usr\""
stub pyenv-virtualenv-prefix "venv33 : echo \"/usr\""
run pyenv-virtualenvs
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
* 3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3) (set by PYENV_VERSION)
venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
venv27 (created from /usr)
* venv33 (created from /usr)
OUT
unstub pyenv-version-name
unstub pyenv-version-origin
unstub pyenv-virtualenv-prefix
}
@test "list bare virtual environments" {
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
@test "list virtual environments with --bare" {
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"/usr\""
stub pyenv-virtualenv-prefix "venv33 : echo \"/usr\""
run pyenv-virtualenvs --bare
assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
venv27
venv33
OUT
}
@test "list bare virtual environments without aliases" {
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --bare --skip-aliases
assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
OUT
}
@test "list virtual environments without aliases" {
stub pyenv-version-name ": echo system"
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --skip-aliases
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
OUT
unstub pyenv-version-name
}
@test "hit prefix matches alias version name" {
stub pyenv-version-name ": echo venv27"
stub pyenv-version-origin ": echo PYENV_VERSION"
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
* venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27 (set by PYENV_VERSION)
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT
unstub pyenv-version-name
unstub pyenv-version-origin
}
@test "completions output" {
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --complete
assert_success
assert_output <<OUT
--bare
--skip-aliases
OUT
unstub pyenv-virtualenv-prefix
}