Virtualenv

There are tons of ways to install Python packages. Some are more convenient, some less so, depending on the situation. I’ll describe the approach that I’ve found most convenient in the majority of cases.

To use it, you don’t need anything except virtualenv and pip themselves.

For each project, I use a separate environment with its own set of packages - I find it easier to manage dependencies this way.

To create environments, I use a small function in ~/.profile:

mkenv() {
  VENV_PATH="$HOME/.python-envs`pwd`"
  virtualenv --no-site-packages -p `which python` $VENV_PATH
  echo "VIRTUALENV_PATH=$VENV_PATH" > .venv
  source $VENV_PATH/bin/activate
}

Environments are created in the hidden folder ~/.python-envs/<path_to_project_folder>, and the path to the environment is written to the project folder in a hidden .venv file. In principle, you could calculate the path, but I’ve already changed the location for new environments a couple of times, and this way there’s no need to move the old ones.

Next, I wanted to somehow automatically activate the environment when I start working with a project. For this purpose, I use another script in ~/.profile that checks for those .venv files. The script triggers when the current directory changes.

PREVPWD=`pwd`
PREVENV_PATH=
PREV_PS1=
PREV_PATH=

handle_virtualenv(){
  if [ "$PWD" != "$PREVPWD" ]; then
    PREVPWD="$PWD";
    if [ -n "$PREVENV_PATH" ]; then
      if [ "`echo "$PWD" | grep -c $PREVENV_PATH`" = "0"  ]; then
         source $PREVENV_PATH/.venv
         echo "> Virtualenv `basename $VIRTUALENV_PATH` deactivated"
         PS1=$PREV_PS1
         PATH=$PREV_PATH
         PREVENV_PATH=
      fi
    fi
    if [ -e "$PWD/.venv" ] && [ "$PWD" != "$PREVENV_PATH" ]; then
      PREV_PS1="$PS1"
      PREV_PATH="$PATH"
      PREVENV_PATH="$PWD"
      source $PWD/.venv
      echo $VIRTUALENV_PATH
      source $VIRTUALENV_PATH/bin/activate
      echo "> Virtualenv `basename $VIRTUALENV_PATH` activated"
    fi
  fi
}

export PROMPT_COMMAND=handle_virtualenv

And that’s basically it. So, what are the benefits?

  • No need to install anything extra, like virtualenvwrapper.
  • It’s easy to track dependencies with pip and see the exact set of packages needed for a specific project.
  • Environments are activated and deactivated automatically, right when you need them.

To avoid fetching packages from the network every time, and also in case PyPI goes down or a nuclear war breaks out, you can also add PIP_DOWNLOAD_CACHE and collective.eggproxy to the mix.