If you work with Python, you probably work with virtualenv. If you work with virtualenv, you probably work with virtualenvwrapper. Nevertheless, if you work a lot with many virtualenvs at the same time, you may become tired of al these “. bin/activate” or “workon smthng”.
You just want to cd into your project directory, and have everyhting ready to work. Especially if you use two-pane file managers, such as Midnight Commander, for file operations and tree browsing, and prefer not to type shell commands when it is not neccessary.
Here is how I do that:
Just put this code into you .bashrc (gist):
# # Print all possible candidates for virtualenv relative to the directory $1. # Used in venv_find() for every directory starting from the current and up to the root. # function venv_candidates () { echo $1 echo $1/.venv echo $1/VENV echo $1/ENV echo $1.venv } # # Finds the closest virtualenv root directory, starting from $1, and going up to the root. # If the target directory is not specified as an argument, current directory is used. # Prints the virtualenv path found, or nothing otherwise. # function venv_find () { local venv_root=${1:-"."} local venv_found="" # The cycle is just for the case with broken root folder detection - never do more than N iterations. for (( i=10; i > 0; i-- )); do local venv_real=$(cd $venv_root && pwd -P) local venv_name=$(basename $venv_real) # echo REAL=$venv_real >&2 for candidate in $( venv_candidates $venv_real ) ; do # echo CANDIDATE=$candidate >&2 if [ -f "$candidate/bin/activate" ]; then echo $(cd $candidate && pwd -P) return fi done if [ "$venv_real" = "/" ]; then break fi venv_root=$venv_root/".." done } # # Find current virtualenv, and prints its path. # NB: The virtualenv must be activated in the current shell, or it will be ignored as if there is # NB: no active virtualenv at all. This is needed because current virtualenv is usually determined # NB: to be deactivated, and if it is not in the current shell, there is no "deactivate" function. # function venv_curr () { if [ -n "$VIRTUAL_ENV" -a "$(type -t deactivate)" = 'function' ]; then echo $VIRTUAL_ENV fi } # # Activates a virtualenv which we are in (or in any of its subfolders), according to our cwd. # Deactivates any virtualenv when we leave it (cd to a directory with no venv at all). # function venv_auto () { venv_new="$(venv_find)" venv_old="$(venv_curr)" bash_cmd=`basename $(expr "$BASH_COMMAND" : "\([^ ]*\)")` # Special case for subshells - they will reactivate their own venv inside. This is needed # to properly keep "deactivate" function inside subshells, and avoid recursive venvs. if [ -n "$venv_old" -a \( "$bash_cmd" == "mc" -o "$bash_cmd" == "bash" -o "$bash_cmd" == "sh" \) ]; then deactivate elif [ -z "$venv_new" -a -n "$venv_old" ]; then deactivate elif [ -n "$venv_new" -a "$venv_new" != "$venv_old" ]; then source "$venv_new"/bin/activate prompt_colorize fi } # # Attach automatic virtualenv detection for any command or action in the shell. # Works well even if you change dirs in mc. # trap venv_auto DEBUG
Now, when you open a shell again, you can do something like that (“nolar” is my username, “nolair” is my computer name, “alpha” and “betta” are virtualenvs):
nolair:~ nolar$ cd alpha (alpha)nolair:alpha nolar$ which python /Users/nolar/alpha/bin/python (alpha)nolair:alpha nolar$ cd ../betta (betta)nolair:betta nolar$ which python /Users/nolar/betta/bin/python (betta)nolair:betta nolar$ cd .. nolair:~ nolar$ which python /usr/bin/python nolair:~ nolar$
The same will happen when you change your directory with mc (Midnight Commander). Good luck! :-)