Jun 30 2008

Python and Django Setup for Mac OS X Leopard

Tags: Mac, Python, Django, Technical

Even though Leopard ships with a fairly recent version of Python (2.5.1), there are several reasons one would want to use an alternative installation. For instance, Python 2.3.5 shipped with Tiger and was growing pretty long in the tooth by the time Leopard arrived; 2.3 was the default installation on Panther.

I've tried a few approaches to installing newer versions on the Mac: several years ago, I played around with Fink, then switched to MacPorts (formerly DarwinPorts). While either of these package managers make it very easy to install various software pacakages on the Mac, they each presented certain problems or limitations with respect to Python and the other web development packages I need.

My current preferred solution is to go with the MacPython distribution found on the Python website. There is also a great SIG (http://mail.python.org/mailman/listinfo/pythonmac-sig) for getting help.

From http://www.python.org/download/mac/:

Python comes pre-installed on Mac OS X, but due to Apple's release cycle, it's often one or even two years old. The overwhelming recommendation of the "MacPython" community is to upgrade your Python by downloading and installing a newer version.

Listed below are the steps to setting up some of the most common Python packages used to for web development, particularly with respect to Django.

Getting started

Basic assumptions

  • Mac OS X Leopard (10.5) - as of the date of this posting, I am on 10.5.3

  • Subversion - you can find an installer at http://subversion.tigris.org/

  • I use MySQL, so instructions for installing it and the necessary Python bindings (MySQLdb) are shown. If anyone has detailed instructions for Postgres installation, please send them to me at python [at] dakrauth.com

  • An installation directory to use for these steps. For instance, here's how I began (from a Terminal window, bash shell):

    1
    2
    3
    mkdir -p ~/python/install
    mkdir ~/python/site-packages
    cd ~/python/install
    

    I use ~/python/site-packages as an easy way of referencing packages that will change frequently or for creating a pseudo-virtual environment. More on this below.

Installations

Python 2.5.2

  • MacPython installation:

    1
    2
    3
    4
    curl -O http://www.python.org/ftp/python/2.5.2/python-2.5.2-macosx.dmg
    open python-2.5.2-macosx.dmg
    open /Volumes/Universal\ MacPython\ 2.5.2/MacPython.mpkg
    hdiutil unmount /Volumes/Universal\ MacPython\ 2.5.2/
    

    This installation will create the site-packages directory at:

    /Library/Frameworks/Python.framework/Versions/Current/lib/python2.5/site-packages
    

    Additionally, your .profile file will be updated to place the above path at the front of you $PATH environment variable. I usually remove this change, since the only thing I like to have my .profile file a source line to my .bashrc file. However, I ensure that /usr/local/bin is place ahead /usr/bin in my $PATH string.

  • Now I set up the ties to the aforementioned local site-packages directory:

    1
    2
    3
    pushd /Library/Frameworks/Python.framework/Versions/Current/lib/python2.5/site-packages
    echo /Users/your-username/python/site-packages > my.pth
    popd
    

MySQL

  • Lines 4, 5, and 6 below are a quick hack around an odd bug in the installer.

    1
    2
    3
    4
    5
    6
    curl -O http://mirror.services.wisc.edu/mysql/Downloads/MySQL-5.0/mysql-5.0.51b-osx10.5-x86.dmg
    open mysql-5.0.51b-osx10.5-x86.dmg
    open /Volumes/mysql-5.0.51b-osx10.5-x86/mysql-5.0.51b-osx10.5-x86.pkg/
    pushd /usr/local/mysql/lib
    sudo ln -s /usr/local/mysql/lib mysql
    popd
    
  • Add the preference pane to your System Preferences and start the server from the preference pane (I also prefer to select Automatically Start MySQL Server on Startup):

    1
    2
    open /Volumes/mysql-5.0.51b-osx10.5-x86/MySQL.prefPane/
    hdiutil unmount /Volumes/mysql-5.0.51b-osx10.5-x86/
    
  • To setup a sample database to use with a Django project, here are the commands I issue from within the mysql shell:

    1
    2
    3
    4
    5
    6
    CREATE DATABASE spam_db 
      CHARACTER SET utf8 
            COLLATE utf8_general_ci;
    GRANT ALL PRIVILEGES ON spam_db.* 
                         TO 'spam_db_user'@'localhost' 
              IDENTIFIED BY 'spam_db_password';
    

MySQLdb

  • MySQLdb provides the Python bindings to interface with the database.

    1
    2
    3
    curl -O http://internap.dl.sourceforge.net/sourceforge/mysql-python/MySQL-python-1.2.2.tar.gz
    tar -xvzf MySQL-python-1.2.2.tar.gz 
    cd MySQL-python-1.2.2
    
  • Edit the site.cfg file:

    • Uncomment the line that begins #mysql_config =

    • Edit the path to point to /usr/local/mysql/bin/mysql_config:

      mysql_config = /usr/local/mysql/bin/mysql_config
      
  • Complete the build and installation:

    1
    2
    3
    python setup.py build
    sudo python setup.py install
    cd ..
    

PIL

The Python Imaging Library adds image processing capabilities and supports many file formats. Probably on of the most common applications I use it for are resizing and cropping images, and generating thumbnail images. This installation seems to cause many people grief, particularly JPEG handling (which is an optional install that depends upon libjpeg).

  • freetype (optional) - a software font engine

    1
    2
    3
    4
    5
    6
    7
    curl -O http://download.savannah.gnu.org/releases/freetype/freetype-2.3.6.tar.gz
    tar -xvzf freetype-2.3.6.tar.gz
    cd freetype-2.3.6
    ./configure
    make
    sudo make install
    cd ..
    
  • libjpeg

    1
    2
    3
    4
    5
    6
    7
    8
    curl -O http://www.ijg.org/files/jpegsrc.v6b.tar.gz
    tar -xvzf jpegsrc.v6b.tar.gz
    cd jpeg-6b
    ./configure
    make
    make test
    sudo make install-lib
    cd ..
    
  • PIL build

    1
    2
    3
    4
    curl -O http://effbot.org/media/downloads/Imaging-1.1.6.tar.gz
    tar -xvzf Imaging-1.1.6.tar.gz
    cd Imaging-1.1.6
    python setup.py build_ext -i
    

    Checking for the following lines near the end of the output from the previous command:

    --- TKINTER support ok
    --- JPEG support ok
    --- ZLIB (PNG/ZIP) support ok
    --- FREETYPE2 support ok
    

    Complet install and perform a last sanity check:

    1
    2
    3
    4
    python selftest.py
    sudo python setup.py install
    python -c "import Image; Image.open('Images/lena.jpg').show()"
    cd ..
    

    You should see a Preview window pop up with the picure of a woman wearing a hat.

Common Packages

  • IPython - An enhanced Python shell. You will want it - and be lost without it very quickly. Django will look for IPython when you run the shell command extension.

    1
    2
    3
    4
    5
    6
    7
    curl -O http://ipython.scipy.org/dist/ipython-0.8.4.tar.gz
    tar -xvzf ipython-0.8.4.tar.gz
    cd ipython-0.8.4
    python setup.py build
    sudo python setup.py install
    python setup.py install_scripts --install-dir=/usr/local/bin
    cd ..
    
  • docutils

    1
    2
    3
    4
    5
    6
    curl -O http://internap.dl.sourceforge.net/sourceforge/docutils/docutils-0.5.tar.gz
    tar -xvzf docutils-0.5.tar.gz 
    cd docutils-0.5
    python setup.py install
    sudo cp tools/buildhtml.py tools/rst2html.py /usr/local/bin
    cd ..
    
  • Markdown

    1
    2
    3
    4
    5
    curl -O http://internap.dl.sourceforge.net/sourceforge/python-markdown/markdown-1.7.tar.gz
    tar -xvzf markdown-1.7.tar.gz 
    cd markdown-1.7
    sudo python setup.py install
    cd ..
    

Django

Installation of Django, using either Apache with mod_python, mod_wsgi, or FastCGI has been written about in numerous locations. However, here is my personal strategy for managing Django across various revisions:

  • First, I set up a directory to store the revisions of Django that I need across the sites I manage:

    1
    2
    mkdir ~/python/django
    pushd ~/python/django
    
  • Next, I have two helper scripts I use to manage my revisions:

    A revision "getter" called djget:

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash
    svn export -r $1 http://code.djangoproject.com/svn/django/trunk $1
    pushd $1/docs
    buildhtml.py --local
    mkdir html
    mv *.html html
    popd
    

    Run djget to export your desired revisions (why not just to stick to one revision? I manage a few sites and not all are on the same revision. Also, I like to play around with the trunk tip on my local machine first before deploying it live).

    Example:

    djget 7728
    

    This will export the desired revision into a directory named for the revision number (7728, in this case). It also generates HTML files from the reStructuredText documentation and moves those files into a new html directory

    A revision switcher called switch:

    1
    2
    3
    4
    5
    6
    #!/bin/bash
    if [ -e django ]; then rm django; fi
    if [ -e html ]; then rm html; fi
    ln -s $1/django
    ln -s $1/docs/html
    

    Example:

    switch 7728
    

    This deletes existing symlinks to another revision and recreates them accordingly.

  • I add the html symlinked directory to my Bookmarks Bar in Safari

  • Finally, I symlink the django symlink in my local site-packages:

    1
    2
    3
    pushd ~/python/site-pacakges
    ln -s ~/python/django/django
    popd
    

Optional packages

  • extensions - a repository for collecting global custom management extensions for the Django Framework. As a contributor to the repository, I would be remiss I neglected to mention it.

    1
    2
    3
    4
    5
    curl -O http://django-command-extensions.googlecode.com/files/django-command-extensions-0.3.tgz
    tar -xvzf django-command-extensions-0.3.tgz
    cd django-command-extensions-0.3
    sudo python setup.py install
    cd ..
    

    - or -

    An example of how I use symlinks in my local site-packages to handle scenarios where I am frequently updating packages:

    1
    2
    3
    4
    svn co http://django-command-extensions.googlecode.com/svn/trunk/ django-command-extensions
    pushd ~/python/site-packages/
    ln -s ~/python/install/django-command-extensions/extensions
    popd
    

    To use in your projects, just add 'extensions' to your INSTALLED_APPS settings.py file (details).

  • Pygments - a generic syntax highlighter for general use in all kinds of software such as forum systems, wikis or other applications that need to prettify source code

    1
    2
    3
    4
    5
    curl -O http://pypi.python.org/packages/source/P/Pygments/Pygments-0.10.tar.gz
    tar -xvzf Pygments-0.10.tar.gz 
    cd Pygments-0.10
    sudo python setup.py  install
    cd ..
    
  • mdx_codehilite - markdown code highlighting extension can be installed as well (requires Pygments):

    1
    2
    3
    4
    5
    6
    curl -o mdx_codehilite-0.2.tar.gz \
    http://gitorious.org/projects/python-markdown-extra/repos/codehilite/\
    archive/f30802583958c9f54e8b4390d8dafa8dd4a147fa.tar.gz
    tar -xvzf mdx_codehilite-0.2.tar.gz 
    cp -v python-markdown-extra-codehilite/mdx_codehilite.py \
        /Library/Frameworks/Python.framework/Versions/Current/lib/python2.5/site-packages
    

    mdx_codehilite is used to added syntax highlighting markup to this blog

  • dateutil - provides powerful extensions to the standard datetime module

    1
    2
    3
    4
    5
    curl -O http://labix.org/download/python-dateutil/python-dateutil-1.4.tar.bz2
    tar -xvjf python-dateutil-1.4.tar.bz2 
    cd python-dateutil-1.4
    sudo python setup.py install
    cd ..
    


  • path - provides a class (path) for working with files and directories (less typing than os.path)

    1
    2
    3
    4
    5
    curl -O http://pypi.python.org/packages/source/p/path.py/path-2.2.zip
    unzip path-2.2.zip 
    cd path-2.2
    sudo python setup.py install
    cd ..
    

    I've used the path package for years, but many people are adopting Unipath

  • twill - a scripting system for automating Web browsing. Useful for testing Web pages or grabbing data from password-protected sites automatically.

    1
    2
    3
    4
    5
    curl -O http://darcs.idyll.org/~t/projects/twill-0.9.tar.gz
    tar -xvzf twill-0.9.tar.gz 
    cd twill-0.9
    sudo python setup.py install
    cd ..
    
  • feedparser - Parse RSS and Atom feeds in Python

    1
    2
    3
    4
    5
    curl -O http://pypi.python.org/packages/source/F/FeedParser/feedparser-4.1.tar.gz
    tar -xvzf feedparser-4.1.tar.gz 
    cd feedparser-4.1
    sudo python setup.py install
    cd ..
    

Miscellany

  • Here are a few aliases I have set in my ~/.bashrc file for developing on Leopard:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/bin/bash
    # System helpers
    # Flush DNS - after making changes to your `/etc/hosts` file:
    alias flushdns='dscacheutil -flushcache'
    # List of open ports
    alias ports='sudo lsof -i -P'
    # Python helpers:
    alias site-packages='cd /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/'
    alias pyclean='find . -name "*.pyc" -exec rm {} \;'
    # Django helpers:
    alias runserver='python manage.py runserver'
    alias runserver0='python manage.py runserver 0.0.0.0:8888'
    alias djshell='python manage.py shell'
    # TextMate helpers:
    export SVN_EDITOR="mate -w"
    export EDITOR="mate -w"