Set Up Python and Install Django on Mac OS X Lion 10.7
August 30, 2011NOTE: This guide was written for Lion 10.7 and has since been superceded by these new guides:
First steps
Lion has done away with the “Sites” folder by default, but it’s easy to add it back — the custom icon will even show up automatically. Use the Finder, or enter the following in a Terminal session:
mkdir ~/Sites
Another change is the hidden ~/Library folder. We can make it visible again with the following command (which gets overridden by OS updates and must be run again afterwards):
chflags nohidden ~/Library/
Since Lion is a full 64-bit system, we’ll save some headaches by letting our compiler know that all compilation should assume 64 bits. Open ~/.bash_profile …
vim ~/.bash_profile
… and add:
# Set architecture flags
export ARCHFLAGS="-arch x86_64"
With those first steps out of the way, now it’s time to get the necessary compilation tools in place.
Compiler
Installing development-related software in the past has required the compiler tool-chain that comes with Xcode. Thankfully, if you don’t need or want Xcode, those compiler tools are now available separately, saving download time and many gigabytes of disk space. Assuming you have your Apple ID credentials handy, head over to the Developer Downloads area, download the Command Line Tools for Xcode, and install it.
Alternatively, if you need Xcode for Mac/iOS app development or find yourself occasionally using it to manually compile open-source Mac applications, download Xcode from either the Developer Downloads area or the Mac App Store. Make sure you’re on a high-bandwidth connection, because Xcode is a massive beast. Once you’ve installed Xcode, launch the Xcode application, visit the app preferences, find the “Downloads” pane, and download the above-mentioned Command Line Tools from within the Xcode application.
Homebrew
Sometimes you may need cross-platform software — usually without a GUI and accessible only via the command line — that isn’t readily available via the Mac App Store. As someone who used MacPorts for years, I can’t begin to explain the relative awesomeness that is Homebrew. It’s an indispensable tool that should be in every Mac developer’s arsenal, so let’s fire up Terminal.app and install it:
ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"
That’s it — Homebrew is now installed. While it should have the latest version of Homebrew and its formulae, let’s run the update command just in case:
brew update
If the “brew update” command produces an error, make sure /usr/local is owned by you and not by root:
sudo chown $USER /usr/local
brew update
The Homebrew wiki has a full command list and a bunch of other useful information, but here’s a quick command to install some packages that I often find useful:
brew install bash-completion byobu ssh-copy-id wget
You can run “brew info byobu”, for example, if you want to know what those packages do.
Python site-packages
Let’s say you want to install a Python package, such as the fantastic virtualenv environment isolation tool. Nearly every Python-related article for Mac OS X tells the reader to install it via sudo easy_install virtualenv
. Here’s why I don’t do it that way:
- installs with root permissions
- installs into the global /Library instead of the user’s
- “Distribute” has less bugs than the default legacy easy_install
If I install a Python package and decide I want to delete it, I like having the option to use the Finder to drag it to the Trash without any permission-related complaints. Plus, keeping the Python packages isolated to the user account just makes more sense to me. Last but not least, Distribute is a fork of Setuptools/easy_install that aims to be more reliable with less bugs.
Traditionally, I’ve always used the --user
flag to install Python packages into ~/.local, a behavior that was consistent across Macs, Linux, and other UNIX systems. It seems Lion has changed this behavior, however, installing into ~/Library/Python/2.7 when it encounters the --user
flag. Since I prefer to have this location remain consistent across the various systems I encounter, I changed the flag from --user
to the more specific --prefix=~/.local
. Whichever you choose, please keep in mind that the instructions here assume the latter.
With that tangent behind us, let’s install Distribute:
mkdir -p ~/.local/lib/python2.7/site-packages
wget http://pypi.python.org/packages/source/d/distribute/distribute-0.6.28.tar.gz
tar -xzf distribute-0.6.28.tar.gz
cd distribute-0.6.28
python setup.py install --prefix=~/.local
The only disadvantage of installing into ~/.local is that we need to add some locations to the PATH and PYTHONPATH environment variables. Let’s edit our .bash_profile…
vim ~/.bash_profile
… and add a few lines:
# Path ------------------------------------------------------------
if [ -d ~/.local/bin ]; then
export PATH=~/.local/bin:$PATH
fi
# Python path -----------------------------------------------------
if [ -d ~/.local/lib/python2.7/site-packages ]; then
export PYTHONPATH=~/.local/lib/python2.7/site-packages:$PYTHONPATH
fi
# Load in .bashrc -------------------------------------------------
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
Let’s load those directives now via:
touch ~/.bashrc
source ~/.bash_profile
Lion’s easy_install is normally located in /usr/bin, so let’s make sure that our local version is the one that’s used by default:
which easy_install
Assuming the response is ~/.local/bin/easy_install, then we’re all set!
virtualenv and virtualenvwrapper
Python packages installed to ~/.local are indeed local to the user, but they are also global in the sense that they are available across all of a given user’s projects. That can be convenient at times, but it also creates problems. For example, sometimes one project needs the latest version of Django, while another needs Django 1.3 to retain compatibility with a critical third-party extension. This is precisely the problem that virtualenv was designed to solve. On my systems, virtualenv, virtualenvwrapper, and Mercurial are the only Python packages that are always available — every other package is confined to its virtual environment.
Let’s install virtualenv and its companion virtualenvwrapper:
easy_install --prefix=~/.local virtualenv virtualenvwrapper
We’ll then open/create the ~/.bashrc file…
vim ~/.bashrc
… and add some lines to it:
# Turn on advanced bash completion if the file exists
if [ -f /usr/local/etc/bash_completion ]; then
. /usr/local/etc/bash_completion
fi
# Locate virtualenvwrapper binary
if [ -f ~/.local/bin/virtualenvwrapper.sh ]; then
export VENVWRAP=~/.local/bin/virtualenvwrapper.sh
fi
if [ ! -z $VENVWRAP ]; then
# virtualenvwrapper -------------------------------------------
# make sure env directory exists; else create it
[ -d $HOME/sites/env ] || mkdir -p $HOME/sites/env
export WORKON_HOME=$HOME/sites/env
source $VENVWRAP
# virtualenv --------------------------------------------------
export VIRTUALENV_USE_DISTRIBUTE=true
# pip ---------------------------------------------------------
export PIP_VIRTUALENV_BASE=$WORKON_HOME
export PIP_REQUIRE_VIRTUALENV=true
export PIP_RESPECT_VIRTUALENV=true
export PIP_DOWNLOAD_CACHE=$HOME/.pip/cache
fi
Let’s re-load our bash environment again:
source ~/.bash_profile
I also add two customizations to virtualenv’s postactivate script, which defines what happens after activating a virtual environment:
vim ~/sites/env/postactivate
Add the following lines, taking note of the comments to see what benefits they offer:
proj_name=${VIRTUAL_ENV##*/}
# Add the active project to the PYTHONPATH
if [ -d ~/sites/env/$proj_name/lib/python2.7/site-packages ]; then
add2virtualenv ~/sites/env/$proj_name/lib/python2.7/site-packages
fi
# "cd" into the virtualenv, or its "project" folder if there is one
if [ -d ~/sites/env/$proj_name/project ]; then
cd ~/sites/env/$proj_name/project
else
cd ~/sites/env/$proj_name
fi
Now we have virtualenv and virtualenvwrapper installed and ready to create new virtual environments, which will be stored in ~/sites/env/.
Version control
Lion comes with git, which is a welcome addition. I’m partial to Mercurial, so for those that want both options, the following command will do the trick:
easy_install --prefix=~/.local Mercurial
At a minimum, you’ll need to add a few lines to your .hgrc file in order to use Mercurial:
vim ~/.hgrc
The following lines should get you started; just be sure to change the values to your name and email address, respectively:
[ui]
username = YOUR NAME <address@example.com>
To test whether Mercurial is configured and ready for use, run the following command:
hg debuginstall
If the last line in the response is “No problems detected”, then Mercurial has been installed and configured properly.
Creating virtual environments
Let’s create a virtual environment called “foobar”:
mkvirtualenv foobar
That should create a new virtual environment and automatically switch our present working directory to that new foobar environment.
In the future, when you want to work on a project contained in a virtual environment, use the “workon” command followed by the name of the virtual environment:
workon foobar
That will activate the “foobar” virtual environment, and if you’ve made the changes I recommended earlier to the “postactivate” script, you should be taken directly to the virtual environment’s directory at ~/sites/env/foobar. If not, you can always get there via the “cdvirtualenv” command, which will take you to the currently-active virtual environment’s home.
First Django project
Assuming our current working directory is our new “foobar” virtual environment, let’s create a folder within called “project” that will contain all of our to-be-versioned files:
mkdir project
While the quick way to install Django would be…
pip install Django
… a better way is to define our project’s dependencies in a requirements file:
vim project/requirements.txt
Our requirements at this point are very simple — just Django. So the contents of our requirements.txt file should just be:
Django
We can then install Django via:
pip install -r project/requirements.txt
We’ll use Django’s “startproject” command to create a new site within our “project” folder:
django-admin.py startproject mysite project/
We can now start Django’s development web server…
cd project
python manage.py runserver
… and see the results in our web browser. For those that are new to Django, the Django Tutorial is a good place to learn how to continue building your project.
First commit
Now that you have a Django project started, use your preferred version control system to make your first commit. For Mercurial, that would be:
hg init project
cd project
hg add
hg commit -m "Initial commit"
By versioning your projects from the very beginning, you’ll always know how (and hopefully why) you’ve made your changes along the way.
Dotfiles
While I’ve posted excerpts of my dotfiles above, you can get the whole enchilada on GitHub.
Phew!
Congrats! It takes a bit of time to set up a new system, but it’s well worth the journey. These are the tools of our trade, and we use them every day, so it makes sense to make them as efficient as possible.