# -*- mode: shell-script -*-
# Shell functions to act as wrapper for Ian Bicking's virtualenv
# (http://pypi.python.org/pypi/virtualenv)
# Copyright Doug Hellmann, All Rights Reserved
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of Doug Hellmann not be used
# in advertising or publicity pertaining to distribution of the software
# without specific, written prior permission.
# DOUG HELLMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
# EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# Project home page: http://www.doughellmann.com/projects/virtualenvwrapper/
# 1. Create a directory to hold the virtual environments.
# (mkdir $HOME/.virtualenvs).
# 2. Add a line like "export WORKON_HOME=$HOME/.virtualenvs"
# 3. Add a line like "source /path/to/this/file/virtualenvwrapper.sh"
# 4. Run: source ~/.bashrc
# 6. A list of environments, empty, is printed.
# 7. Run: mkvirtualenv temp
# 9. This time, the "temp" environment is included.
# 11. The virtual environment is activated.
# Locate the global Python where virtualenvwrapper is installed.
if [ "$VIRTUALENVWRAPPER_PYTHON" = "" ]
VIRTUALENVWRAPPER_PYTHON="$(command \which python)"
# Set the name of the virtualenv app to use.
if [ "$VIRTUALENVWRAPPER_VIRTUALENV" = "" ]
VIRTUALENVWRAPPER_VIRTUALENV="virtualenv"
# Set the name of the virtualenv-clone app to use.
if [ "$VIRTUALENVWRAPPER_VIRTUALENV_CLONE" = "" ]
VIRTUALENVWRAPPER_VIRTUALENV_CLONE="virtualenv-clone"
# Define script folder depending on the platorm (Win32/Unix)
VIRTUALENVWRAPPER_ENV_BIN_DIR="bin"
if [ "$OS" = "Windows_NT" ] && ([ "$MSYSTEM" = "MINGW32" ] || [ "$MSYSTEM" = "MINGW64" ])
# Only assign this for msys, cygwin use standard Unix paths
# and its own python installation
VIRTUALENVWRAPPER_ENV_BIN_DIR="Scripts"
# Let the user override the name of the file that holds the project
if [ "$VIRTUALENVWRAPPER_PROJECT_FILENAME" = "" ]
export VIRTUALENVWRAPPER_PROJECT_FILENAME=".project"
# Let the user tell us they never want to cd to projects
export VIRTUALENVWRAPPER_WORKON_CD=${VIRTUALENVWRAPPER_WORKON_CD:-1}
# Remember where we are running from.
if [ -z "$VIRTUALENVWRAPPER_SCRIPT" ]
export VIRTUALENVWRAPPER_SCRIPT="$BASH_SOURCE"
elif [ -n "$ZSH_VERSION" ]
export VIRTUALENVWRAPPER_SCRIPT="$0"
export VIRTUALENVWRAPPER_SCRIPT="${.sh.file}"
# Portable shell scripting is hard, let's go shopping.
# People insist on aliasing commands like 'cd', either with a real
# alias or even a shell function. Under bash and zsh, "builtin" forces
# the use of a command that is part of the shell itself instead of an
# alias, function, or external command, while "command" does something
# similar but allows external commands. Under ksh "builtin" registers
# a new command from a shared library, but "command" will pick up
# existing builtin commands. We need to use a builtin for cd because
# we are trying to change the state of the current shell, so we use
# "builtin" for bash and zsh but "command" under ksh.
function virtualenvwrapper_cd {
elif [ -n "$ZSH_VERSION" ]
function virtualenvwrapper_expandpath {
"$VIRTUALENVWRAPPER_PYTHON" -c "import os,sys; sys.stdout.write(os.path.normpath(os.path.expanduser(os.path.expandvars(\"$1\")))+'\n')"
function virtualenvwrapper_absolutepath {
"$VIRTUALENVWRAPPER_PYTHON" -c "import os,sys; sys.stdout.write(os.path.abspath(\"$1\")+'\n')"
function virtualenvwrapper_derive_workon_home {
typeset workon_home_dir="$WORKON_HOME"
# Make sure there is a default value for WORKON_HOME.
# You can override this setting in your .bashrc.
if [ "$workon_home_dir" = "" ]
workon_home_dir="$HOME/.virtualenvs"
# If the path is relative, prefix it with $HOME
# (note: for compatibility)
if echo "$workon_home_dir" | (unset GREP_OPTIONS; command \grep '^[^/~]' > /dev/null)
workon_home_dir="$HOME/$WORKON_HOME"
# Only call on Python to fix the path if it looks like the
# path might contain stuff to expand.
# (it might be possible to do this in shell, but I don't know a
# cross-shell-safe way of doing it -wolever)
if echo "$workon_home_dir" | (unset GREP_OPTIONS; command \egrep '([\$~]|//)' >/dev/null)
# This will normalize the path by:
# - Removing extra slashes (e.g., when TMPDIR ends in a slash)
# - Expanding variables (e.g., $foo)
# - Converting ~s to complete paths (e.g., ~/ to /home/brian/ and ~arthur to /home/arthur)
workon_home_dir="$(virtualenvwrapper_expandpath "$workon_home_dir")"
# Check if the WORKON_HOME directory exists,
# create it if it does not
# seperate from creating the files in it because this used to just error
# and maybe other things rely on the dir existing before that happens.
function virtualenvwrapper_verify_workon_home {
if [ ! -d "$WORKON_HOME/" ]
echo "NOTE: Virtual environments directory $WORKON_HOME does not exist. Creating..." 1>&2
#HOOK_VERBOSE_OPTION="-q"
# Function to wrap mktemp so tests can replace it for error condition
function virtualenvwrapper_mktemp {
# Expects 1 argument, the suffix for the new file.
function virtualenvwrapper_tempfile {
# Note: the 'X's must come last
typeset suffix=${1:-hook}
file="$(virtualenvwrapper_mktemp -t virtualenvwrapper-$suffix-XXXXXXXXXX)"
if [ $? -ne 0 ] || [ -z "$file" ] || [ ! -f "$file" ]
echo "ERROR: virtualenvwrapper could not create a temporary file name." 1>&2
function virtualenvwrapper_run_hook {
hook_script="$(virtualenvwrapper_tempfile ${1}-hook)" || return 1
# Use a subshell to run the python interpreter with hook_loader so
# we can change the working directory. This avoids having the
# Python 3 interpreter decide that its "prefix" is the virtualenv
# if we happen to be inside the virtualenv when we start.
virtualenvwrapper_cd "$WORKON_HOME" &&
"$VIRTUALENVWRAPPER_PYTHON" -m 'virtualenvwrapper.hook_loader' \
$HOOK_VERBOSE_OPTION --script "$hook_script" "$@" \
if [ ! -f "$hook_script" ]
echo "ERROR: virtualenvwrapper_run_hook could not find temporary file $hook_script" 1>&2
command \rm -f "$hook_script"
elif [ "${1}" = "initialize" ]
virtualenvwrapper.sh: There was a problem running the initialization hooks.
If Python could not import the module virtualenvwrapper.hook_loader,
check that virtualenvwrapper has been installed for
VIRTUALENVWRAPPER_PYTHON=$VIRTUALENVWRAPPER_PYTHON and that PATH is
command \rm -f "$hook_script"
# Set up tab completion. (Adapted from Arthur Koziel's version at
# http://arthurkoziel.com/2008/10/11/virtualenvwrapper-bash-completion/)
function virtualenvwrapper_setup_tab_completion {
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=( $(compgen -W "`virtualenvwrapper_show_workon_options`" -- ${cur}) )
_cdvirtualenv_complete () {
COMPREPLY=( $(cdvirtualenv && compgen -d -- "${cur}" ) )
_cdsitepackages_complete () {
COMPREPLY=( $(cdsitepackages && compgen -d -- "${cur}" ) )
complete -o nospace -F _cdvirtualenv_complete -S/ cdvirtualenv
complete -o nospace -F _cdsitepackages_complete -S/ cdsitepackages
complete -o default -o nospace -F _virtualenvs workon
complete -o default -o nospace -F _virtualenvs rmvirtualenv
complete -o default -o nospace -F _virtualenvs cpvirtualenv
complete -o default -o nospace -F _virtualenvs showvirtualenv
elif [ -n "$ZSH_VERSION" ] ; then
reply=( $(virtualenvwrapper_show_workon_options) )
_cdvirtualenv_complete () {
reply=( $(cdvirtualenv && ls -d ${1}*) )
_cdsitepackages_complete () {
reply=( $(cdsitepackages && ls -d ${1}*) )
compctl -K _virtualenvs workon rmvirtualenv cpvirtualenv showvirtualenv
compctl -K _cdvirtualenv_complete cdvirtualenv
compctl -K _cdsitepackages_complete cdsitepackages
# Set up virtualenvwrapper properly
function virtualenvwrapper_initialize {
export WORKON_HOME="$(virtualenvwrapper_derive_workon_home)"
virtualenvwrapper_verify_workon_home -q || return 1
# Set the location of the hook scripts
if [ "$VIRTUALENVWRAPPER_HOOK_DIR" = "" ]
export VIRTUALENVWRAPPER_HOOK_DIR="$WORKON_HOME"
mkdir -p "$VIRTUALENVWRAPPER_HOOK_DIR"
virtualenvwrapper_run_hook "initialize"
virtualenvwrapper_setup_tab_completion
# Verify that the passed resource is in path and exists
function virtualenvwrapper_verify_resource {
typeset exe_path="$(command \which "$1" | (unset GREP_OPTIONS; command \grep -v "not found"))"
echo "ERROR: virtualenvwrapper could not find $1 in your path" >&2
echo "ERROR: Found $1 in path as \"$exe_path\" but that does not exist" >&2
# Verify that virtualenv is installed and visible
function virtualenvwrapper_verify_virtualenv {
virtualenvwrapper_verify_resource $VIRTUALENVWRAPPER_VIRTUALENV
function virtualenvwrapper_verify_virtualenv_clone {
virtualenvwrapper_verify_resource $VIRTUALENVWRAPPER_VIRTUALENV_CLONE
# Verify that the requested environment exists
function virtualenvwrapper_verify_workon_environment {
if [ ! -d "$WORKON_HOME/$env_name" ]
echo "ERROR: Environment '$env_name' does not exist. Create it with 'mkvirtualenv $env_name'." >&2
# Verify that the active environment exists
function virtualenvwrapper_verify_active_environment {
if [ ! -n "${VIRTUAL_ENV}" ] || [ ! -d "${VIRTUAL_ENV}" ]
echo "ERROR: no virtualenv active, or active virtualenv is missing" >&2
# Help text for mkvirtualenv
function virtualenvwrapper_mkvirtualenv_help {
echo "Usage: mkvirtualenv [-a project_path] [-i package] [-r requirements_file] [virtualenv options] env_name"
echo " Provide a full path to a project directory to associate with"
echo " the new environment."
echo " Install a package after the environment is created."
echo " This option may be repeated."
echo " -r requirements_file"
echo " Provide a pip requirements file to install a base set of packages"
echo " into the new environment."
"$VIRTUALENVWRAPPER_VIRTUALENV" $@;
# Create a new environment, in the WORKON_HOME.
# Usage: mkvirtualenv [options] ENVNAME
# (where the options are passed directly to virtualenv)
#:help:mkvirtualenv: Create a new virtualenv in $WORKON_HOME
echo "Cannot associate project with $project, it is not a directory" 1>&2
project="$(virtualenvwrapper_absolutepath ${project})";;
virtualenvwrapper_mkvirtualenv_help $a;
packages="$packages ${in_args[$i]}";;
if echo "$a" | grep -q "="
interpreter="$(echo "$a" | cut -f2 -d=)"
interpreter="${in_args[$i]}"
requirements="${in_args[$i]}";
requirements="$(virtualenvwrapper_expandpath "$requirements")";;
if [ ${#out_args} -gt 0 ]
out_args=( "${out_args[@]-}" "$a" )
out_args=( "--python=$interpreter" ${out_args[@]} )
virtualenvwrapper_verify_workon_home || return 1
virtualenvwrapper_verify_virtualenv || return 1
[ -n "$ZSH_VERSION" ] && setopt SH_WORD_SPLIT
virtualenvwrapper_cd "$WORKON_HOME" &&
"$VIRTUALENVWRAPPER_VIRTUALENV" $VIRTUALENVWRAPPER_VIRTUALENV_ARGS "$@" &&
[ -d "$WORKON_HOME/$envname" ] && \
virtualenvwrapper_run_hook "pre_mkvirtualenv" "$envname"
[ $RC -ne 0 ] && return $RC
# If they passed a help option or got an error from virtualenv,
# the environment won't exist. Use that to tell whether
# we should switch to the environment and run the hook.
[ ! -d "$WORKON_HOME/$envname" ] && return 0
# If they gave us a project directory, set it up now
# so the activate hooks can find it.
setvirtualenvproject "$WORKON_HOME/$envname" "$project"
[ $RC -ne 0 ] && return $RC
# Now activate the new environment
if [ ! -z "$requirements" ]