• CV
  • Blog
  • Contacts
    • Facebook
    • LinkedIn
    • GitHub
    • Twitter
    • Google+
    • LiveJournal
    • VK
  • РусскийРусский

Anamnesis

of a kooky software developer with megalomaniacal inferiority complex

Automatically activate virtualenv on cd (even in mc)

27.07.2012 by Sergey Vasilyev 3 Comments

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! :-)

Posted in: Development, Life Hacks Tagged: bash, python, shell, venv, virtualenv, workon

Categories

Development Job Knowhows Life Hacks Management Nothings Traveling Word of the Day

Tags

amazon apple archive aws backup blog budget business canada capslock career cloud development document english expenses experiment file image iq job keyboard keyremap4macbook language layout lifehack macbook mac os x macosx management password pckeyboardhack photo psychology python russia russian startup storage success team toronto us windows workon

Copyright © 2025 Anamnesis.

Omega WordPress Theme by ThemeHall