virtualenv to the Rescue

Deploying Python applications is not that hard, but there are some pitfalls. The main problem everyone stumbles upon sooner or later is that sys.modules is a singleton. Modules are cached there which the effect that there can be exaclty one version of a library loaded at the same time per interpreter. There is no way around that and it’s fine. However there is another problem: Everyone installs everything into a system wide singleton called site-packages. Sooner or later everything ends up there, and while pkg_sources supports switching between versions this is very unconfortable and requires extra hackery.

My plan to solve these problems always was creating a folder, putting all libraries into that folder and site.addsitedir()ing that folder in the file that starts up the application. But especially for web applications that’s a dull repetitive task and easy_install and other libraries don’t play well with this approach.

Fortunately Ian Bicking wrote a really cool module called “virtualenv” that creates virtual Python environments. And it does that in a very cool manner. The following example shows how we run LodgeIt on our server:

First you need to install virtualenv. This assumes you already have easy_install:

mitsuhiko@nausicaa:~$ sudo easy_install virtualenv
Searching for virtualenv
Reading http://pypi.python.org/simple/virtualenv/
Best match: virtualenv 1.1
Downloading virtualenv-1.1-py2.5.egg
Processing virtualenv-1.1-py2.5.egg
creating /opt/local/lib/python2.5/site-packages/virtualenv-1.1-py2.5.egg
Extracting virtualenv-1.1-py2.5.egg to /opt/local/lib/python2.5/site-packages
Adding virtualenv 1.1 to easy-install.pth file
Installing virtualenv script to /opt/local/bin

Installed /opt/local/lib/python2.5/site-packages/virtualenv-1.1-py2.5.egg
Processing dependencies for virtualenv
Finished processing dependencies for virtualenv

Now we can create a folder folder the application. In our case the folder is called after the domain where the web application runs:

mitsuhiko@nausicaa:~$ virtualenv paste.pocoo.org
New python executable in paste.pocoo.org/bin/python
Installing setuptools.......................done.

The virtual python is now available in that folder and we can switch into that environment by sourcing the activate file:

mitsuhiko@nausicaa:$ cd paste.pocoo.org/
mitsuhiko@nausicaa:~/paste.pocoo.org$ . bin/activate
(paste.pocoo.org)mitsuhiko@nausicaa:~/paste.pocoo.org$

From that point onwards “python” and “easy_install” point to the executables in the ~/paste.pocoo.org/bin folder. The prompt is prefixed with the name of the virtual environment so that we are reminded that “python” is our virtual Python. We can now install all the dependencies:

$ easy_install SQLAlchemy==0.4.4 Jinja2 Werkzeug Pygments

Half a minute later the virtual python interpreter will now have the libraries available and we’re ready to add out application:

$ hg clone http://dev.pocoo.org/hg/lodgeit-main

Lodgeit itself doesn’t have a setup.py file but we can just cd into the folder and run the testing server to test if it works:

$ cd lodgeit-main/
$ python runlodgeit.py runserver
 * Running on http://localhost:5000/
 * Restarting with reloader...

That works perfectly for scripts invoking “python” directly such as standalone servers like CherryPy but won’t work for mod_wsgi where the interpreter is created by mod_wsgi and doesn’t point to the virtual environment.

There are two ways to solve the problem. For mod_wsgi 2.0 you can run the web application in daemon mode and pass it the path to the site packages in the apache config:

WSGIDaemonProcess lodgeit python-path=/path/to/site-packages

Alternatively you can go into the .wsgi file and add the site-packages by hand:

import site
site.addsitedir("/path/to/site-packages")

The site-packages of the virtual environment are located at /path/to/virtual/env/lib/python2.X/site-packages.

Even though I was not interested in virtualenv in the beginning I changed my mind because it’s straightforward to use and easy to maintain. More information about virtualenv is available in the Cheeseshop and the announcement blog post in Ian’s blog.

4 Responses to “virtualenv to the Rescue”

  1. Very cool! I always have this problem when there are 2-3 projects going on at a time and the site-packages is full of modules that each one requires. Have to check this out now.

    Comment by Siddharta — Sunday, July 6th, 2008 @ 1:47 am
  2. Worth noting is that in mod_wsgi 2.0 (for daemon mode), the reason that:

    python-path=/path/to/site-packages

    works is that mod_wsgi, rather than just adding these directories to sys.path, it is underneath actually calling site.addsitedir() for each directory listed. Without this, the .pth files in the directories wouldn’t be read and processed and so eggs wouldn’t work. It does this to specifically be friendly with both virtualenv type setups and eggs.

    If using embedded mode of mod_wsgi 2.0, the WSGIPythonPath directive does the same thing. There is a bit more to it than that though if you want to have the site-packages directory in your Python installation totally ignored due to it filling up with crap over time. More details can be found in:

    http://code.google.com/p/modwsgi/wiki/VirtualEnvironments

    Comment by Graham Dumpleton — Sunday, July 6th, 2008 @ 2:08 am
  3. Just in case if someone got a problem on OpenSUSE > 10.0:-

    http://groups.google.com/group/python-virtualenv/browse_thread/thread/aa69f8b738d23652

    I happily use virtualenv before but stopped using it after upgrading to opensuse 10.3 and got hit by that ‘bug’.

    Comment by k4ml — Sunday, July 13th, 2008 @ 9:34 am
  4. Nice post. Hopefully it will bring more people to use this valuable tool. I have done a screencast which showcases virtualenv’s abilities:

    http://www.showmedo.com/videos/video?name=2910000&fromSeriesID=291

    enjoy.
    -chris

    Comment by Chris Perkins — Tuesday, July 22nd, 2008 @ 3:27 pm

Leave a Reply

cogitations driven by wordpress