How can a shell function know if it is running within a virtualenv?
Solution 1
Actually, I just found a similar question, from which one can easily derive an answer to this one:
Python: Determine if running inside virtualenv
E.g., a shell script can use something like
python -c 'import sys; print (sys.real_prefix)' 2>/dev/null && INVENV=1 || INVENV=0
(Thanks to Christian Long for showing how to make this solution work with Python 3 also.)
EDIT: Here's a more direct (hence clearer and cleaner) solution (taking a cue from JuanPablo's comment):
INVENV=$(python -c 'import sys; print ("1" if hasattr(sys, "real_prefix") else "0")')
Solution 2
if [[ "$VIRTUAL_ENV" != "" ]]
then
INVENV=1
else
INVENV=0
fi
// or shorter if you like:
[[ "$VIRTUAL_ENV" == "" ]]; INVENV=$?
EDIT: as @ThiefMaster mentions in the comments, in certain conditions (for instance, when starting a new shell – perhaps in tmux
or screen
– from within an active virtualenv) this check may fail (however, starting new shells from within a virtualenv may cause other issues as well, I wouldn't recommend it).
Solution 3
If you use virtualenvwrappers there are pre/post scripts that run that could set INVENV for you.
Or what I do, put the following in your your .bashrc, and make a file called .venv in your working directory (for django) so that the virtual env is automatically loaded when you cd into the directory
export PREVPWD=`pwd`
export PREVENV_PATH=
handle_virtualenv(){
if [ "$PWD" != "$PREVPWD" ]; then
PREVPWD="$PWD";
if [ -n "$PREVENV_PATH" ]; then
if [ "`echo "$PWD" | grep -c $PREVENV_PATH`" = "0" ]; then
deactivate
unalias python 2> /dev/null
PREVENV_PATH=
fi
fi
# activate virtualenv dynamically
if [ -e "$PWD/.venv" ] && [ "$PWD" != "$PREVENV_PATH" ]; then
PREVENV_PATH="$PWD"
workon `basename $PWD`
if [ -e "manage.py" ]; then
alias python='python manage.py shell_plus'
fi
fi
fi
}
export PROMPT_COMMAND=handle_virtualenv
kjo
Updated on January 31, 2022Comments
-
kjo over 2 years
How should a
bash
function test whether it is running inside a Python virtualenv?The two approaches that come to mind are:
[[ "$(type -t deactivate)" != function ]]; INVENV=$?
or
[[ "x$(which python)" != "x$VIRTUAL_ENV/bin/python" ]]; INVENV=$?
(Note: wanting
$INVENV
to be 1 if we're inside a virtualenv, and 0 otherwise, is what forces the backward-looking tests above.)Is there something less hacky?
-
kjo about 11 yearsI avoided this approach because I've had situations in which
$VIRTUAL_ENV
was set, but (for some reason), not in$PATH
... -
robertklep about 11 yearsNot sure what
$PATH
has to do with it? Or do you mean you want to check if your current working directory is part of a virtualenv? -
kjo about 11 yearssorry for my confusing comment; if
$VIRTUAL_ENV
is not in$PATH
then thepython
executable that gets used by everything else will not be the one in the virtualenv. By itself, assigning a value to$VIRTUAL_ENV
does nothing. -
kjo about 11 yearsThanks for the code. BTW, I think that bash already maintains
OLDPWD
, which the same thing asPREVPWD
in your code. -
robertklep about 11 yearsI agree, but my snippet doesn't assign to
$VIRTUAL_ENV
, it checks for it. When it exists, it means a virtual environment is active (that variable is set by theactivate
script and unset bydeactivate
). Which is what you wanted, right? -
James Mills almost 11 yearsI found this particular solution valid and worked well for me. Exactly what I was after. Thanks! :)
-
ThiefMaster over 10 yearsThis is not reliable. For example, in tmux sessions started while inside a virtualenv the venv is not active but $VIRTUAL_ENV is still set.
-
ThiefMaster over 10 yearsMight be a good idea to mention it in your answer that it can fail in some cases
-
JuanPablo over 10 yearsa optional command for check :
python -c 'import sys; print hasattr(sys, "real_prefix")'
-
Christian Long almost 9 yearsAdd parentheses to support Python 3
python -c 'import sys; print(sys.real_prefix)' 2>/dev/null && INVENV=1 || INVENV=0
-
BrendanSimon over 4 yearsMy python env (
python3 -m venv venv
) does not have thesys.real_prefix
attribute. Would this be ok as an alternative?INVENV=$( python -c 'import sys ; print( 0 if sys.prefix == sys.base_prefix else 1 )' )
-
Broshi about 4 years@BrendanSimon looks fine to me.
-
quanta almost 4 yearsWorks when run directly on the terminal, doesn't appear to be working from inside a bash script (running inside a venv)!
-
Dostrelith about 2 yearsRunning inside a simple bash script, this answer worked for me (you can also echo the
$VIRTUAL_ENV
for debugging). The accepted answer did not work from inside a bash script. -
Dostrelith about 2 yearsYou can also cast it to
int()
instead of the if statement:INVENV=$(python3 -c 'import sys; print(int(hasattr(sys, "real_prefix")))')
However, running from a simple bash script I could not get confirmation that the script is using the venv. The answer below using$VIRTUAL_ENV
variable (set by sourcing theactivate
script) did.