Skip to content

Commit e5ce384

Browse files
authored
Export VIRTUAL_ENV_PROMPT in activation scripts (#2194) (#2606)
1 parent cda7f22 commit e5ce384

File tree

13 files changed

+90
-61
lines changed

13 files changed

+90
-61
lines changed

docs/changelog/2194.feature.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Export the prompt prefix as ``VIRTUAL_ENV_PROMPT`` when activating a virtual
2+
environment - by :user:`jimporter`.

docs/user_guide.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,10 @@ Note that you don't have to activate a virtual environment to use it. You can in
242242
executables, rather than relying on your shell to resolve them to your virtual environment.
243243

244244
Activator scripts also modify your shell prompt to indicate which environment is currently active, by prepending the
245-
environment name in brackets, like ``(venv)``. You can disable this behaviour by setting the environment variable
246-
``VIRTUAL_ENV_DISABLE_PROMPT`` to any value.
245+
environment name (or the name specified by ``--prompt`` when initially creating the environment) in brackets, like
246+
``(venv)``. You can disable this behaviour by setting the environment variable ``VIRTUAL_ENV_DISABLE_PROMPT`` to any
247+
value. You can also get the environment name via the environment variable ``VIRTUAL_ENV_PROMPT`` if you want to
248+
customize your prompt, for example.
247249

248250
The scripts also provision a ``deactivate`` command that will allow you to undo the operation:
249251

src/virtualenv/activation/bash/activate.sh

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ deactivate () {
3535
fi
3636

3737
unset VIRTUAL_ENV
38+
unset VIRTUAL_ENV_PROMPT
3839
if [ ! "${1-}" = "nondestructive" ] ; then
3940
# Self destruct!
4041
unset -f deactivate
@@ -54,6 +55,13 @@ _OLD_VIRTUAL_PATH="$PATH"
5455
PATH="$VIRTUAL_ENV/__BIN_NAME__:$PATH"
5556
export PATH
5657

58+
if [ "x__VIRTUAL_PROMPT__" != x ] ; then
59+
VIRTUAL_ENV_PROMPT="__VIRTUAL_PROMPT__"
60+
else
61+
VIRTUAL_ENV_PROMPT=$(basename "$VIRTUAL_ENV")
62+
fi
63+
export VIRTUAL_ENV_PROMPT
64+
5765
# unset PYTHONHOME if set
5866
if ! [ -z "${PYTHONHOME+_}" ] ; then
5967
_OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME"
@@ -62,11 +70,7 @@ fi
6270

6371
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then
6472
_OLD_VIRTUAL_PS1="${PS1-}"
65-
if [ "x__VIRTUAL_PROMPT__" != x ] ; then
66-
PS1="(__VIRTUAL_PROMPT__) ${PS1-}"
67-
else
68-
PS1="(`basename \"$VIRTUAL_ENV\"`) ${PS1-}"
69-
fi
73+
PS1="(${VIRTUAL_ENV_PROMPT}) ${PS1-}"
7074
export PS1
7175
fi
7276

src/virtualenv/activation/batch/activate.bat

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
@set "VIRTUAL_ENV=__VIRTUAL_ENV__"
22

3+
@set "VIRTUAL_ENV_PROMPT=__VIRTUAL_PROMPT__"
4+
@if NOT DEFINED VIRTUAL_ENV_PROMPT (
5+
@for %%d in ("%VIRTUAL_ENV%") do @set "VIRTUAL_ENV_PROMPT=%%~nxd"
6+
)
7+
38
@if defined _OLD_VIRTUAL_PROMPT (
49
@set "PROMPT=%_OLD_VIRTUAL_PROMPT%"
510
) else (
@@ -11,11 +16,7 @@
1116
)
1217
)
1318
@if not defined VIRTUAL_ENV_DISABLE_PROMPT (
14-
@if "__VIRTUAL_PROMPT__" NEQ "" (
15-
@set "PROMPT=(__VIRTUAL_PROMPT__) %PROMPT%"
16-
) else (
17-
@for %%d in ("%VIRTUAL_ENV%") do @set "PROMPT=(%%~nxd) %PROMPT%"
18-
)
19+
@set "PROMPT=(%VIRTUAL_ENV_PROMPT%) %PROMPT%"
1920
)
2021

2122
@REM Don't use () to avoid problems with them in %PATH%

src/virtualenv/activation/batch/deactivate.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@set VIRTUAL_ENV=
2+
@set VIRTUAL_ENV_PROMPT=
23

34
@REM Don't use () to avoid problems with them in %PATH%
45
@if not defined _OLD_VIRTUAL_PROMPT @goto ENDIFVPROMPT

src/virtualenv/activation/cshell/activate.csh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
set newline='\
66
'
77

8-
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH:q" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT:q" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
8+
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH:q" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT:q" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
99

1010
# Unset irrelevant variables.
1111
deactivate nondestructive
@@ -18,9 +18,9 @@ setenv PATH "$VIRTUAL_ENV:q/__BIN_NAME__:$PATH:q"
1818

1919

2020
if ('__VIRTUAL_PROMPT__' != "") then
21-
set env_name = '(__VIRTUAL_PROMPT__) '
21+
setenv VIRTUAL_ENV_PROMPT '__VIRTUAL_PROMPT__'
2222
else
23-
set env_name = '('"$VIRTUAL_ENV:t:q"') '
23+
setenv VIRTUAL_ENV_PROMPT "$VIRTUAL_ENV:t:q"
2424
endif
2525

2626
if ( $?VIRTUAL_ENV_DISABLE_PROMPT ) then
@@ -42,7 +42,7 @@ if ( $do_prompt == "1" ) then
4242
if ( "$prompt:q" =~ *"$newline:q"* ) then
4343
:
4444
else
45-
set prompt = "$env_name:q$prompt:q"
45+
set prompt = '('"$VIRTUAL_ENV_PROMPT:q"') '"$prompt:q"
4646
endif
4747
endif
4848
endif

src/virtualenv/activation/fish/activate.fish

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ function deactivate -d 'Exit virtualenv mode and return to the normal environmen
4444
end
4545

4646
set -e VIRTUAL_ENV
47+
set -e VIRTUAL_ENV_PROMPT
4748

4849
if test "$argv[1]" != 'nondestructive'
4950
# Self-destruct!
@@ -67,6 +68,14 @@ else
6768
end
6869
set -gx PATH "$VIRTUAL_ENV"'/__BIN_NAME__' $PATH
6970

71+
# Prompt override provided?
72+
# If not, just use the environment name.
73+
if test -n '__VIRTUAL_PROMPT__'
74+
set -gx VIRTUAL_ENV_PROMPT '__VIRTUAL_PROMPT__'
75+
else
76+
set -gx VIRTUAL_ENV_PROMPT (basename "$VIRTUAL_ENV")
77+
end
78+
7079
# Unset `$PYTHONHOME` if set.
7180
if set -q PYTHONHOME
7281
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
@@ -85,13 +94,7 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
8594
# Run the user's prompt first; it might depend on (pipe)status.
8695
set -l prompt (_old_fish_prompt)
8796

88-
# Prompt override provided?
89-
# If not, just prepend the environment name.
90-
if test -n '__VIRTUAL_PROMPT__'
91-
printf '(%s) ' '__VIRTUAL_PROMPT__'
92-
else
93-
printf '(%s) ' (basename "$VIRTUAL_ENV")
94-
end
97+
printf '(%s) ' $VIRTUAL_ENV_PROMPT
9598

9699
string join -- \n $prompt # handle multi-line prompts
97100
end

src/virtualenv/activation/nushell/activate.nu

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,24 @@ export-env {
4646
let venv_path = ([$virtual_env $bin] | path join)
4747
let new_path = ($env | get $path_name | prepend $venv_path)
4848

49+
# If there is no default prompt, then use the env name instead
50+
let virtual_env_prompt = (if ('__VIRTUAL_PROMPT__' | is-empty) {
51+
($virtual_env | path basename)
52+
} else {
53+
'__VIRTUAL_PROMPT__'
54+
})
55+
4956
let new_env = {
50-
$path_name : $new_path
51-
VIRTUAL_ENV : $virtual_env
57+
$path_name : $new_path
58+
VIRTUAL_ENV : $virtual_env
59+
VIRTUAL_ENV_PROMPT : $virtual_env_prompt
5260
}
5361

5462
let new_env = (if (is-env-true 'VIRTUAL_ENV_DISABLE_PROMPT') {
5563
$new_env
5664
} else {
5765
# Creating the new prompt for the session
58-
let virtual_prompt = (if ('__VIRTUAL_PROMPT__' | is-empty) {
59-
$'(char lparen)($virtual_env | path basename)(char rparen) '
60-
} else {
61-
'(__VIRTUAL_PROMPT__) '
62-
})
66+
let virtual_prefix = $'(char lparen)($virtual_env_prompt)(char rparen) '
6367

6468
# Back up the old prompt builder
6569
let old_prompt_command = (if (has-env 'PROMPT_COMMAND') {
@@ -68,20 +72,19 @@ export-env {
6872
''
6973
})
7074

71-
# If there is no default prompt, then only the env is printed in the prompt
7275
let new_prompt = (if (has-env 'PROMPT_COMMAND') {
7376
if 'closure' in ($old_prompt_command | describe) {
74-
{|| $'($virtual_prompt)(do $old_prompt_command)' }
77+
{|| $'($virtual_prefix)(do $old_prompt_command)' }
7578
} else {
76-
{|| $'($virtual_prompt)($old_prompt_command)' }
79+
{|| $'($virtual_prefix)($old_prompt_command)' }
7780
}
7881
} else {
79-
{|| $'($virtual_prompt)' }
82+
{|| $'($virtual_prefix)' }
8083
})
8184

8285
$new_env | merge {
8386
PROMPT_COMMAND : $new_prompt
84-
VIRTUAL_PROMPT : $virtual_prompt
87+
VIRTUAL_PREFIX : $virtual_prefix
8588
}
8689
})
8790

src/virtualenv/activation/powershell/activate.ps1

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ function global:deactivate([switch] $NonDestructive) {
1616
Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue
1717
}
1818

19+
if ($env:VIRTUAL_ENV_PROMPT) {
20+
Remove-Item env:VIRTUAL_ENV_PROMPT -ErrorAction SilentlyContinue
21+
}
22+
1923
if (!$NonDestructive) {
2024
# Self destruct!
2125
Remove-Item function:deactivate
@@ -33,6 +37,13 @@ deactivate -nondestructive
3337
$VIRTUAL_ENV = $BASE_DIR
3438
$env:VIRTUAL_ENV = $VIRTUAL_ENV
3539

40+
if ("__VIRTUAL_PROMPT__" -ne "") {
41+
$env:VIRTUAL_ENV_PROMPT = "__VIRTUAL_PROMPT__"
42+
}
43+
else {
44+
$env:VIRTUAL_ENV_PROMPT = $( Split-Path $env:VIRTUAL_ENV -Leaf )
45+
}
46+
3647
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
3748

3849
$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
@@ -42,19 +53,9 @@ if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
4253
}
4354
$function:_old_virtual_prompt = $function:prompt
4455

45-
if ("__VIRTUAL_PROMPT__" -ne "") {
46-
function global:prompt {
47-
# Add the custom prefix to the existing prompt
48-
$previous_prompt_value = & $function:_old_virtual_prompt
49-
("(__VIRTUAL_PROMPT__) " + $previous_prompt_value)
50-
}
51-
}
52-
else {
53-
function global:prompt {
54-
# Add a prefix to the current prompt, but don't discard it.
55-
$previous_prompt_value = & $function:_old_virtual_prompt
56-
$new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) "
57-
($new_prompt_value + $previous_prompt_value)
58-
}
56+
function global:prompt {
57+
# Add the custom prefix to the existing prompt
58+
$previous_prompt_value = & $function:_old_virtual_prompt
59+
("(" + $env:VIRTUAL_ENV_PROMPT + ") " + $previous_prompt_value)
5960
}
6061
}

src/virtualenv/activation/python/activate_this.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# prepend bin to PATH (this file is inside the bin directory)
2424
os.environ["PATH"] = os.pathsep.join([bin_dir, *os.environ.get("PATH", "").split(os.pathsep)])
2525
os.environ["VIRTUAL_ENV"] = base # virtual env is right above bin directory
26+
os.environ["VIRTUAL_ENV_PROMPT"] = "__VIRTUAL_PROMPT__" or os.path.basename(base) # noqa: SIM222
2627

2728
# add the virtual environments libraries to the host python import mechanism
2829
prev_length = len(sys.path)

tests/unit/activation/conftest.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,36 +114,42 @@ def _get_test_lines(self, activate_script):
114114
return [
115115
self.print_python_exe(),
116116
self.print_os_env_var("VIRTUAL_ENV"),
117+
self.print_os_env_var("VIRTUAL_ENV_PROMPT"),
117118
self.activate_call(activate_script),
118119
self.print_python_exe(),
119120
self.print_os_env_var("VIRTUAL_ENV"),
121+
self.print_os_env_var("VIRTUAL_ENV_PROMPT"),
120122
self.print_prompt(),
121123
# \\ loads documentation from the virtualenv site packages
122124
self.pydoc_call,
123125
self.deactivate,
124126
self.print_python_exe(),
125127
self.print_os_env_var("VIRTUAL_ENV"),
128+
self.print_os_env_var("VIRTUAL_ENV_PROMPT"),
126129
"", # just finish with an empty new line
127130
]
128131

129132
def assert_output(self, out, raw, tmp_path):
130133
# pre-activation
131134
assert out[0], raw
132135
assert out[1] == "None", raw
136+
assert out[2] == "None", raw
133137
# post-activation
134138
expected = self._creator.exe.parent / os.path.basename(sys.executable)
135-
assert self.norm_path(out[2]) == self.norm_path(expected), raw
136-
assert self.norm_path(out[3]) == self.norm_path(self._creator.dest).replace("\\\\", "\\"), raw
139+
assert self.norm_path(out[3]) == self.norm_path(expected), raw
140+
assert self.norm_path(out[4]) == self.norm_path(self._creator.dest).replace("\\\\", "\\"), raw
141+
assert out[5] == self._creator.env_name
137142
# Some attempts to test the prompt output print more than 1 line.
138143
# So we need to check if the prompt exists on any of them.
139144
prompt_text = f"({self._creator.env_name}) "
140-
assert any(prompt_text in line for line in out[4:-3]), raw
145+
assert any(prompt_text in line for line in out[6:-4]), raw
141146

142-
assert out[-3] == "wrote pydoc_test.html", raw
147+
assert out[-4] == "wrote pydoc_test.html", raw
143148
content = tmp_path / "pydoc_test.html"
144149
assert content.exists(), raw
145150
# post deactivation, same as before
146-
assert out[-2] == out[0], raw
151+
assert out[-3] == out[0], raw
152+
assert out[-2] == "None", raw
147153
assert out[-1] == "None", raw
148154

149155
def quote(self, s):

tests/unit/activation/test_nushell.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def __init__(self, session) -> None:
1919
self.unix_line_ending = not IS_WIN
2020

2121
def print_prompt(self):
22-
return r"print $env.VIRTUAL_PROMPT"
22+
return r"print $env.VIRTUAL_PREFIX"
2323

2424
def activate_call(self, script):
2525
# Commands are called without quotes in Nushell

tests/unit/activation/test_python_activator.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def print_r(value):
4141
print(repr(value))
4242
4343
print_r(os.environ.get("VIRTUAL_ENV"))
44+
print_r(os.environ.get("VIRTUAL_ENV_PROMPT"))
4445
print_r(os.environ.get("PATH").split(os.pathsep))
4546
print_r(sys.path)
4647
@@ -51,6 +52,7 @@ def print_r(value):
5152
exec(content, {{"__file__": file_at}})
5253
5354
print_r(os.environ.get("VIRTUAL_ENV"))
55+
print_r(os.environ.get("VIRTUAL_ENV_PROMPT"))
5456
print_r(os.environ.get("PATH").split(os.pathsep))
5557
print_r(sys.path)
5658
@@ -62,24 +64,27 @@ def print_r(value):
6264
def assert_output(self, out, raw, tmp_path): # noqa: ARG002
6365
out = [literal_eval(i) for i in out]
6466
assert out[0] is None # start with VIRTUAL_ENV None
67+
assert out[1] is None # likewise for VIRTUAL_ENV_PROMPT
6568

66-
prev_path = out[1]
67-
prev_sys_path = out[2]
68-
assert out[3] == str(self._creator.dest) # VIRTUAL_ENV now points to the virtual env folder
69+
prev_path = out[2]
70+
prev_sys_path = out[3]
71+
assert out[4] == str(self._creator.dest) # VIRTUAL_ENV now points to the virtual env folder
6972

70-
new_path = out[4] # PATH now starts with bin path of current
73+
assert out[5] == str(self._creator.env_name) # VIRTUAL_ENV_PROMPT now has the env name
74+
75+
new_path = out[6] # PATH now starts with bin path of current
7176
assert ([str(self._creator.bin_dir), *prev_path]) == new_path
7277

7378
# sys path contains the site package at its start
74-
new_sys_path = out[5]
79+
new_sys_path = out[7]
7580

7681
new_lib_paths = {str(i) for i in self._creator.libs}
7782
assert prev_sys_path == new_sys_path[len(new_lib_paths) :]
7883
assert new_lib_paths == set(new_sys_path[: len(new_lib_paths)])
7984

8085
# manage to import from activate site package
8186
dest = self.norm_path(self._creator.purelib / "pydoc_test.py")
82-
found = self.norm_path(out[6])
87+
found = self.norm_path(out[8])
8388
assert found.startswith(dest)
8489

8590
def non_source_activate(self, activate_script):

0 commit comments

Comments
 (0)