Making Virtualenv Play Nice with Git
January 19th, 2010 — 5 Comments — Permalink
I like to do most of my Python development inside virtualenvs. I also create a Git repository for any project that matters or that will have any kind of continued development. Constantly switching between the different virtualenvs to work on different projects used to be tedious, but this issue was largely solved by the fantastic virtualenvwrapper.
Virtualenvwrapper has certainly improved the situation, but even so, I can't help but worry that the cd project-x, workon project-x, (do some work), cd .., deactivate work-flow is going to lead me to an early grave caused by a severe case of RSI. So in order to retain my good health, I've hacked together a bash function that automatically activates a virtualenv when you cd into a Git repository, and deactivates it when you leave the repository.
By default, it assumes that the virtualenv's name will be the same as the repository's name, but this can be overridden by creating a file called .venv in the repository's root directory with the name of another virtualenv in it.
# Automatically activate Git projects' virtual environments based on the # directory name of the project. Virtual environment name can be overridden # by placing a .venv file in the project root with a virtualenv name in it function workon_cwd { # Check that this is a Git repo GIT_DIR=`git rev-parse --git-dir 2> /dev/null` if [ $? == 0 ]; then # Find the repo root and check for virtualenv name override GIT_DIR=`\cd $GIT_DIR; pwd` PROJECT_ROOT=`dirname "$GIT_DIR"` ENV_NAME=`basename "$PROJECT_ROOT"` if [ -f "$PROJECT_ROOT/.venv" ]; then ENV_NAME=`cat "$PROJECT_ROOT/.venv"` fi # Activate the environment only if it is not already active if [ "$VIRTUAL_ENV" != "$WORKON_HOME/$ENV_NAME" ]; then if [ -e "$WORKON_HOME/$ENV_NAME/bin/activate" ]; then workon "$ENV_NAME" && export CD_VIRTUAL_ENV="$ENV_NAME" fi fi elif [ $CD_VIRTUAL_ENV ]; then # We've just left the repo, deactivate the environment # Note: this only happens if the virtualenv was activated automatically deactivate && unset CD_VIRTUAL_ENV fi } # New cd function that does the virtualenv magic function venv_cd { cd "$@" && workon_cwd } alias cd="venv_cd"
Note: for this to work you will need virtualenv and virtualenvwrapper installed. To use it, just stick it in your .bashrc somewhere below where your $WORKON_HOME is specified.
Discussion
Leave A Reply
You may use Markdown syntax but raw HTML will be escaped and headings normalised.
Great idea. I don't (currently) use Git at work but a quick modification to just check for .venv works a treat. Thanks
You can take another approach by creating a
postactivatebash script and placing it in your .virtualenvs/myproject/bin directory. This file is executed whenever you switch to that project usingworkon.For instance:
cat ~/.virtualenvs/myproject/bin/postactivate
!/bin/bash
cd /var/www/myproject
So
workon myprojectautomatically switches to that working direcory. Saves on typing out paths and such. :)oops, forgot it was markdown...
Phillip: I've seen a couple of people using the
postactivatehook -- seems like a nice alternative approach. I like the idea of automatically updating the repo and running the development server as well.Interesting approach - thank you for sharing. I've also favored the postactivate approach and use it similarly to how Phillip describes. It is great for also configuring environment vars specific to that virtualenv or project. I tend to put code in different places depending on if it is a client project, personal, or just experimentation and I like that "workon <env>" will take me to the root of the project and activate the environment. I don't ever find the need to explicitly deactivate - this happens implicitly whenever you activate a new environment. Also, there's no real danger that I can tell in activating an already activated environment. In fact, I tend to just use "workon <env>" as a canonical way of just navigating back to my project's root no matter where I am in the filesystem and regardless of whether the env is already activated. So my workflow relative to yours is "workon <env1>. workon <env2>..."