SaltyCrane Blog — Notes on JavaScript and web development

Free Computer Science courses online

I found out there is a video lecture series to go along with my new book The Algorithm Design Manual. The audio level is really low, but I think it will complement my book reading nicely. There are also lecture notes and homework assignments. It also turns out MIT has a huge collection of free courses online. Not all of them have video though. I listed some interesting Computer Science related courses with video below. After more searching, I found UC Berkeley also has a number of free courses online, including four Computer Science courses with video. The final source I found was ArsDigita University. They have a good number of Computer Science video lectures as well, but I had a hard time connecting. Let me know if I am missing other good sources.

Update 2009-7-8: I've updated the list to include Stanford's online courses. They have 3 Introduction to Computer Science courses with video lectures and 3 Artificial Intelligence courses with video lectures.

Stony Brook University Courses

MIT Courses

UC Berkeley Courses

Stanford Courses


See also: ArsDigita University Courses

Find the N longest lines in a file with Python

Here's a Python problem I attempted recently:

Write a program to read a multiple line text file and write the N longest lines to a new file. Where N and the file to be read are specified on the command line. Optimization is important.

Here's my solution:

import sys

def main(filename=sys.argv[1], 
         N=int(sys.argv[2])):
    """Find the N longest lines in filename and write to filename + ".new"
    """
    lines = open(filename).readlines()
    lines.sort(cmp=lambda x,y: cmp(len(y), len(x)))
    open(filename+".new", "w").write("".join(lines[:N]))

if __name__ == '__main__':
    main()

What do you think? Is there a faster way?

Notes on using pip and virtualenv with Django

I have been using a symlinking method to install Python packages up to this point. To better handle dependencies and multiple versions I have wanted to switch over to pip and virtualenv. Pip is a better alternative to Easy Install and virtualenv is a tool to create isolated Python environments. I have wanted to use pip and virtualenv for a long time now. Finally, today, I took my first steps and created an environment with the Python packages required for this blog. My notes are below. (I am running Ubuntu IntrepidKarmicMaverick and Python 2.52.6.) A lot of my notes on virtualenv are taken from Arthur Koziel's excellent tutorial.

Update 2012-03-14: Updated examples for pip 1.1 and virtualenv 1.7. As of pip 1.1, the -E option is removed. As of virtualenv 1.7, the --no-site-packages has become the default and is deprecated. Use --system-site-packages if you want to include system site packages (the old default behavior). Examples are run on Ubuntu 10.10 Maverick Meerkat.

Install Easy Install

If you don't already have Easy Install, it can be installed as follows:

$ sudo apt-get install python-setuptools python-dev build-essential

Install pip

In most cases it is not necessary to install pip because it is included with virtualenv.

$ sudo easy_install -U pip 
install_dir /usr/local/lib/python2.6/dist-packages/
Searching for pip
Reading http://pypi.python.org/simple/pip/
Reading http://pip.openplans.org
Reading http://www.pip-installer.org
Best match: pip 1.1
Downloading http://pypi.python.org/packages/source/p/pip/pip-1.1.tar.gz#md5=62a9f08dd5dc69d76734568a6c040508
Processing pip-1.1.tar.gz
Running pip-1.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-i_5nEU/pip-1.1/egg-dist-tmp-ytHsCZ
warning: no files found matching '*.html' under directory 'docs'
warning: no previously-included files matching '*.txt' found under directory 'docs/_build'
no previously-included directories found matching 'docs/_build/_sources'
Adding pip 1.1 to easy-install.pth file
Installing pip script to /usr/local/bin
Installing pip-2.6 script to /usr/local/bin

Installed /usr/local/lib/python2.6/dist-packages/pip-1.1-py2.6.egg
Processing dependencies for pip
Finished processing dependencies for pip

Install virtualenv

$ sudo easy_install -U virtualenv 
install_dir /usr/local/lib/python2.6/dist-packages/
Searching for virtualenv
Reading http://pypi.python.org/simple/virtualenv/
Reading http://www.virtualenv.org
Reading http://virtualenv.openplans.org
Best match: virtualenv 1.7.1.2
Downloading http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.7.1.2.tar.gz#md5=3be8a014c27340f48b56465f9109d9fa
Processing virtualenv-1.7.1.2.tar.gz
Running virtualenv-1.7.1.2/setup.py -q bdist_egg --dist-dir /tmp/easy_install-td3AoM/virtualenv-1.7.1.2/egg-dist-tmp-7dJVfO
warning: no previously-included files matching '*.*' found under directory 'docs/_templates'
Adding virtualenv 1.7.1.2 to easy-install.pth file
Installing virtualenv script to /usr/local/bin

Installed /usr/local/lib/python2.6/dist-packages/virtualenv-1.7.1.2-py2.6.egg
Processing dependencies for virtualenv
Finished processing dependencies for virtualenv

Create a virtual environment

This command creates the isolated virtual environment.

Update 2010-04-13: Updated to use distribute because it is the new hotness.

$ cd /tmp
$ virtualenv --distribute myenv
New python executable in myenv/bin/python
Installing distribute.............................................................................................................................................................................................done.
Installing pip...............done.

Create a virtualenv with a different version of Python

This creates a virtualenv that uses Python 2.7 instead of the default Python 2.6.

$ virtualenv --distribute --python=/usr/bin/python2.7 myenv-py27
Running virtualenv with interpreter /usr/bin/python2.7
New python executable in myenv-py27/bin/python2.7
Also creating executable in myenv-py27/bin/python
Installing distribute.............................................................................................................................................................................................done.
Installing pip...............done.

Clear the PYTHONPATH variable

I don't know if this is necessary, but I had a problem with the akismet module when this was set. Maybe I did something wrong, but when I cleared PYTHONPATH, it worked.

$ export PYTHONPATH=

Install a package (Yolk) in the new virtual environment

Activate the virtual environment and install Yolk inside it. (Yolk is a tool that lists Python packages.)

$ source /tmp/myenv/bin/activate 
$ pip install yolk 
Downloading/unpacking yolk
  Downloading yolk-0.4.3.tar.gz (86Kb): 86Kb downloaded
  Running setup.py egg_info for package yolk
    warning: no files found matching '*.txt' under directory 'tests'
    warning: no files found matching '*.conf' under directory 'docs'
    warning: no files found matching '*.css_t' under directory 'docs'
    warning: no files found matching 'indexsidebar.html' under directory 'docs'
    warning: no files found matching 'tests/test_cli.py'
Requirement already satisfied (use --upgrade to upgrade): distribute in ./myenv/lib/python2.6/site-packages/distribute-0.6.24-py2.6.egg (from yolk)
Installing collected packages: yolk
  Running setup.py install for yolk
    warning: no files found matching '*.txt' under directory 'tests'
    warning: no files found matching '*.conf' under directory 'docs'
    warning: no files found matching '*.css_t' under directory 'docs'
    warning: no files found matching 'indexsidebar.html' under directory 'docs'
    warning: no files found matching 'tests/test_cli.py'
    Installing yolk script to /tmp/myenv/bin
Successfully installed yolk
Cleaning up...

Use the virtual environment

  • Activate the virtual environment
    $ source /tmp/myenv/bin/activate
    
  • Run yolk to list your installed packages:
    $ yolk -l
    Python          - 2.6.6        - active development (/usr/lib/python2.6/lib-dynload)
    distribute      - 0.6.24       - active 
    pip             - 1.1          - active 
    wsgiref         - 0.1.2        - active development (/usr/lib/python2.6)
    yolk            - 0.4.3        - active
    
  • Deactivate the environment
    $ deactivate
    
  • Try running yolk
    $ yolk -l
    yolk: command not found
    

Install Django in the virtual environment

$ source /tmp/myenv/bin/activate
$ pip install Django
Downloading/unpacking Django
  Downloading Django-1.3.1.tar.gz (6.5Mb): 6.5Mb downloaded
  Running setup.py egg_info for package Django
Installing collected packages: Django
  Running setup.py install for Django
    changing mode of build/scripts-2.6/django-admin.py from 644 to 755
    changing mode of /tmp/myenv/bin/django-admin.py to 755
Successfully installed Django
Cleaning up...

Create a requirements file from existing library versions using pip freeze


The pip freeze command allows you to take a snapshot of the exact versions of all your Python libraries. For more information, see the documentation on pip freeze.

$ source /tmp/myenv/bin/activate
$ pip freeze > /tmp/requirements.txt
$ cat /tmp/requirements.txt 
Django==1.3.1
distribute==0.6.24
wsgiref==0.1.2
yolk==0.4.3

Uninstall a package

$ source /tmp/myenv/bin/activate
$ pip uninstall Django
Uninstalling Django:
  /tmp/myenv/bin/django-admin.py
  /tmp/myenv/lib/python2.6/site-packages/Django-1.3.1-py2.6.egg-info
  /tmp/myenv/lib/python2.6/site-packages/django
Proceed (y/n)? y
  Successfully uninstalled Django

Install libraries based on a requirements file

Once you have a requirements file, you can use pip to install the exact versions of the libraries specified in your requirements file. For more information, see the documentation on pip requirements files. Here's my requirements file for this blog, /tmp/saltycrane-requirements.txt:

psycopg2==2.4.2
Django==1.3.1
Markdown==2.0
http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.7a.tar.gz
Pygments==1.3.1
Twisted==10.0.0

http://django-tagging.googlecode.com/files/django-tagging-0.3.1.tar.gz
-e hg+http://bitbucket.org/ubernostrum/django-contact-form/#egg=django-contact-form
-e hg+http://bitbucket.org/jezdez/akismet/#egg=akismet

Fabric==1.3.1

Here's the command to install using my reqirements file:

$ source /tmp/myenv/bin/activate
$ pip install -r /tmp/saltycrane-requirements.txt
Downloading/unpacking http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.7a.tar.gz (from -r /tmp/saltycrane-requirements.txt (line 7))
  Downloading BeautifulSoup-3.0.7a.tar.gz
  Running setup.py egg_info for package from http://www.crummy.com/software/BeautifulSoup/download/3.x/Beaut
ifulSoup-3.0.7a.tar.gz                                           
Downloading/unpacking http://django-tagging.googlecode.com/files/django-tagging-0.3.1.tar.gz (from -r /tmp/saltycrane-requirements.txt (line 11))
  Downloading django-tagging-0.3.1.tar.gz
  Running setup.py egg_info for package from http://django-tagging.googlecode.com/files/django-tagging-0.3.1.tar.gz
Downloading/unpacking psycopg2==2.4.2 (from -r /tmp/saltycrane-requirements.txt (line 1))
  Downloading psycopg2-2.4.2.tar.gz (667Kb): 667Kb downloaded
  Running setup.py egg_info for package psycopg2
    no previously-included directories found matching 'doc/src/_build'
Downloading/unpacking Django==1.3.1 (from -r /tmp/saltycrane-requirements.txt (line 4))
  Downloading Django-1.3.1.tar.gz (6.5Mb): 6.5Mb downloaded
  Running setup.py egg_info for package Django
Downloading/unpacking Markdown==2.0 (from -r /tmp/saltycrane-requirements.txt (line 5))
  Downloading Markdown-2.0.zip (93Kb): 93Kb downloaded
  Running setup.py egg_info for package Markdown
Downloading/unpacking Pygments==1.3.1 (from -r /tmp/saltycrane-requirements.txt (line 8))
  Downloading Pygments-1.3.1.tar.gz (1.1Mb): 1.1Mb downloaded
  Running setup.py egg_info for package Pygments
Downloading/unpacking Twisted==10.0.0 (from -r /tmp/saltycrane-requirements.txt (line 9))
  Downloading Twisted-10.0.0.tar.bz2 (2.6Mb): 2.6Mb downloaded
  Running setup.py egg_info for package Twisted
Obtaining django-contact-form from hg+http://bitbucket.org/ubernostrum/django-contact-form/#egg=django-contact-form (from -r /tmp/saltycrane-requirements.txt (line 12))
  Cloning hg http://bitbucket.org/ubernostrum/django-contact-form/ to ./myenv/src/django-contact-form
  Running setup.py egg_info for package django-contact-form
Obtaining akismet from hg+http://bitbucket.org/jezdez/akismet/#egg=akismet (from -r /tmp/saltycrane-requirements.txt (line 13))
  Cloning hg http://bitbucket.org/jezdez/akismet/ to ./myenv/src/akismet
  Running setup.py egg_info for package akismet
Downloading/unpacking Fabric==1.3.1 (from -r /tmp/saltycrane-requirements.txt (line 15))
  Downloading Fabric-1.3.1.tar.gz (167Kb): 167Kb downloaded
  Running setup.py egg_info for package Fabric
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no files found matching 'fabfile.py'
Downloading/unpacking zope.interface (from Twisted==10.0.0->-r /tmp/saltycrane-requirements.txt (line 9))
  Downloading zope.interface-3.8.0.tar.gz (111Kb): 111Kb downloaded
  Running setup.py egg_info for package zope.interface
Downloading/unpacking ssh>=1.7.8 (from Fabric==1.3.1->-r /tmp/saltycrane-requirements.txt (line 15))
  Downloading ssh-1.7.13.tar.gz (790Kb): 790Kb downloaded
  Running setup.py egg_info for package ssh
Requirement already satisfied (use --upgrade to upgrade): distribute in ./myenv/lib/python2.6/site-packages/distribute-0.6.24-py2.6.egg (from zope.interface->Twisted==10.0.0->-r /tmp/saltycrane-requirements.txt (line 9))
Downloading/unpacking pycrypto>=2.1,!=2.4 (from ssh>=1.7.8->Fabric==1.3.1->-r /tmp/saltycrane-requirements.txt (line 15))
  Downloading pycrypto-2.5.tar.gz (426Kb): 426Kb downloaded
  Running setup.py egg_info for package pycrypto
Installing collected packages: psycopg2, Django, Markdown, Pygments, Twisted, django-contact-form, akismet, Fabric, BeautifulSoup, django-tagging, zope.interface, ssh, pycrypto
  Running setup.py install for psycopg2
    building 'psycopg2._psycopg' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/psycopgmodule.c -o build/temp.linux-x86_64-2.6/psycopg/psycopgmodule.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/green.c -o build/temp.linux-x86_64-2.6/psycopg/green.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/pqpath.c -o build/temp.linux-x86_64-2.6/psycopg/pqpath.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/utils.c -o build/temp.linux-x86_64-2.6/psycopg/utils.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/bytes_format.c -o build/temp.linux-x86_64-2.6/psycopg/bytes_format.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/connection_int.c -o build/temp.linux-x86_64-2.6/psycopg/connection_int.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/connection_type.c -o build/temp.linux-x86_64-2.6/psycopg/connection_type.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/cursor_int.c -o build/temp.linux-x86_64-2.6/psycopg/cursor_int.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/cursor_type.c -o build/temp.linux-x86_64-2.6/psycopg/cursor_type.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/lobject_int.c -o build/temp.linux-x86_64-2.6/psycopg/lobject_int.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/lobject_type.c -o build/temp.linux-x86_64-2.6/psycopg/lobject_type.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/notify_type.c -o build/temp.linux-x86_64-2.6/psycopg/notify_type.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/xid_type.c -o build/temp.linux-x86_64-2.6/psycopg/xid_type.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_asis.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_asis.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_binary.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_binary.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_datetime.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_datetime.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_list.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_list.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_pboolean.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_pboolean.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_pdecimal.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_pdecimal.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_pint.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_pint.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_pfloat.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_pfloat.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_qstring.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_qstring.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/microprotocols.c -o build/temp.linux-x86_64-2.6/psycopg/microprotocols.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/microprotocols_proto.c -o build/temp.linux-x86_64-2.6/psycopg/microprotocols_proto.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/typecast.c -o build/temp.linux-x86_64-2.6/psycopg/typecast.o -Wdeclaration-after-statement
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DHAVE_MXDATETIME=1 -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.2 (dt dec mx pq3 ext)" -DPG_VERSION_HEX=0x08040B -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.6/mx -I/usr/include/python2.6 -I. -I/usr/include/postgresql -I/usr/include/postgresql/8.4/server -c psycopg/adapter_mxdatetime.c -o build/temp.linux-x86_64-2.6/psycopg/adapter_mxdatetime.o -Wdeclaration-after-statement
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/psycopg/psycopgmodule.o build/temp.linux-x86_64-2.6/psycopg/green.o build/temp.linux-x86_64-2.6/psycopg/pqpath.o build/temp.linux-x86_64-2.6/psycopg/utils.o build/temp.linux-x86_64-2.6/psycopg/bytes_format.o build/temp.linux-x86_64-2.6/psycopg/connection_int.o build/temp.linux-x86_64-2.6/psycopg/connection_type.o build/temp.linux-x86_64-2.6/psycopg/cursor_int.o build/temp.linux-x86_64-2.6/psycopg/cursor_type.o build/temp.linux-x86_64-2.6/psycopg/lobject_int.o build/temp.linux-x86_64-2.6/psycopg/lobject_type.o build/temp.linux-x86_64-2.6/psycopg/notify_type.o build/temp.linux-x86_64-2.6/psycopg/xid_type.o build/temp.linux-x86_64-2.6/psycopg/adapter_asis.o build/temp.linux-x86_64-2.6/psycopg/adapter_binary.o build/temp.linux-x86_64-2.6/psycopg/adapter_datetime.o build/temp.linux-x86_64-2.6/psycopg/adapter_list.o build/temp.linux-x86_64-2.6/psycopg/adapter_pboolean.o build/temp.linux-x86_64-2.6/psycopg/adapter_pdecimal.o build/temp.linux-x86_64-2.6/psycopg/adapter_pint.o build/temp.linux-x86_64-2.6/psycopg/adapter_pfloat.o build/temp.linux-x86_64-2.6/psycopg/adapter_qstring.o build/temp.linux-x86_64-2.6/psycopg/microprotocols.o build/temp.linux-x86_64-2.6/psycopg/microprotocols_proto.o build/temp.linux-x86_64-2.6/psycopg/typecast.o build/temp.linux-x86_64-2.6/psycopg/adapter_mxdatetime.o -lpq -o build/lib.linux-x86_64-2.6/psycopg2/_psycopg.so
    no previously-included directories found matching 'doc/src/_build'
  Running setup.py install for Django
    changing mode of build/scripts-2.6/django-admin.py from 644 to 755
    changing mode of /tmp/myenv/bin/django-admin.py to 755
  Running setup.py install for Markdown
    changing mode of build/scripts-2.6/markdown.py from 644 to 755
    changing mode of /tmp/myenv/bin/markdown.py to 755
  Running setup.py install for Pygments
    Installing pygmentize script to /tmp/myenv/bin
  Running setup.py install for Twisted
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c conftest.c -o conftest.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c conftest.c -o conftest.o
    building 'twisted.runner.portmap' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c twisted/runner/portmap.c -o build/temp.linux-x86_64-2.6/twisted/runner/portmap.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/twisted/runner/portmap.o -o build/lib.linux-x86_64-2.6/twisted/runner/portmap.so
    building 'twisted.protocols._c_urlarg' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c twisted/protocols/_c_urlarg.c -o build/temp.linux-x86_64-2.6/twisted/protocols/_c_urlarg.o
    twisted/protocols/_c_urlarg.c: In function ‘unquote’:
    twisted/protocols/_c_urlarg.c:41: warning: ‘tmp’ may be used uninitialized in this function
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/twisted/protocols/_c_urlarg.o -o build/lib.linux-x86_64-2.6/twisted/protocols/_c_urlarg.so
    building 'twisted.test.raiser' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c twisted/test/raiser.c -o build/temp.linux-x86_64-2.6/twisted/test/raiser.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/twisted/test/raiser.o -o build/lib.linux-x86_64-2.6/twisted/test/raiser.so
    building 'twisted.python._epoll' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c twisted/python/_epoll.c -o build/temp.linux-x86_64-2.6/twisted/python/_epoll.o
    twisted/python/_epoll.c: In function ‘__pyx_f_6_epoll_5epoll___dealloc__’:
    twisted/python/_epoll.c:168: warning: label ‘__pyx_L1’ defined but not used
    twisted/python/_epoll.c: In function ‘__pyx_f_6_epoll_5epoll_wait’:
    twisted/python/_epoll.c:432: warning: label ‘__pyx_L7’ defined but not used
    twisted/python/_epoll.c:430: warning: label ‘__pyx_L6’ defined but not used
    twisted/python/_epoll.c: In function ‘__pyx_tp_new_6_epoll_epoll’:
    twisted/python/_epoll.c:508: warning: unused variable ‘p’
    twisted/python/_epoll.c: In function ‘__pyx_tp_dealloc_6_epoll_epoll’:
    twisted/python/_epoll.c:513: warning: unused variable ‘p’
    twisted/python/_epoll.c: In function ‘__pyx_tp_traverse_6_epoll_epoll’:
    twisted/python/_epoll.c:528: warning: unused variable ‘p’
    twisted/python/_epoll.c:527: warning: unused variable ‘e’
    twisted/python/_epoll.c: In function ‘__pyx_tp_clear_6_epoll_epoll’:
    twisted/python/_epoll.c:533: warning: unused variable ‘p’
    twisted/python/_epoll.c: At top level:
    twisted/python/_epoll.c:32: warning: ‘__Pyx_UnpackItem’ declared ‘static’ but never defined
    twisted/python/_epoll.c:33: warning: ‘__Pyx_EndUnpack’ declared ‘static’ but never defined
    twisted/python/_epoll.c:34: warning: ‘__Pyx_PrintItem’ declared ‘static’ but never defined
    twisted/python/_epoll.c:35: warning: ‘__Pyx_PrintNewline’ declared ‘static’ but never defined
    twisted/python/_epoll.c:37: warning: ‘__Pyx_ReRaise’ declared ‘static’ but never defined
    twisted/python/_epoll.c:38: warning: ‘__Pyx_Import’ declared ‘static’ but never defined
    twisted/python/_epoll.c:39: warning: ‘__Pyx_GetExcValue’ declared ‘static’ but never defined
    twisted/python/_epoll.c:40: warning: ‘__Pyx_ArgTypeTest’ declared ‘static’ but never defined
    twisted/python/_epoll.c:41: warning: ‘__Pyx_TypeTest’ declared ‘static’ but never defined
    twisted/python/_epoll.c:42: warning: ‘__Pyx_GetStarArgs’ declared ‘static’ but never defined
    twisted/python/_epoll.c:43: warning: ‘__Pyx_WriteUnraisable’ declared ‘static’ but never defined
    twisted/python/_epoll.c:45: warning: ‘__Pyx_ImportType’ declared ‘static’ but never defined
    twisted/python/_epoll.c:46: warning: ‘__Pyx_SetVtable’ declared ‘static’ but never defined
    twisted/python/_epoll.c:47: warning: ‘__Pyx_GetVtable’ declared ‘static’ but never defined
    twisted/python/_epoll.c:48: warning: ‘__Pyx_CreateClass’ declared ‘static’ but never defined
    twisted/python/_epoll.c:50: warning: ‘__Pyx_InitStrings’ declared ‘static’ but never defined
    twisted/python/_epoll.c:51: warning: ‘__Pyx_InitCApi’ declared ‘static’ but never defined
    twisted/python/_epoll.c:52: warning: ‘__Pyx_ImportModuleCApi’ declared ‘static’ but never defined
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/twisted/python/_epoll.o -o build/lib.linux-x86_64-2.6/twisted/python/_epoll.so
    building 'twisted.python._initgroups' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c twisted/python/_initgroups.c -o build/temp.linux-x86_64-2.6/twisted/python/_initgroups.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/twisted/python/_initgroups.o -o build/lib.linux-x86_64-2.6/twisted/python/_initgroups.so
    changing mode of build/scripts-2.6/mktap from 644 to 755
    changing mode of build/scripts-2.6/tap2deb from 644 to 755
    changing mode of build/scripts-2.6/tap2rpm from 644 to 755
    changing mode of build/scripts-2.6/trial from 644 to 755
    changing mode of build/scripts-2.6/pyhtmlizer from 644 to 755
    changing mode of build/scripts-2.6/tapconvert from 644 to 755
    changing mode of build/scripts-2.6/manhole from 644 to 755
    changing mode of build/scripts-2.6/twistd from 644 to 755
    changing mode of build/scripts-2.6/ckeygen from 644 to 755
    changing mode of build/scripts-2.6/cftp from 644 to 755
    changing mode of build/scripts-2.6/conch from 644 to 755
    changing mode of build/scripts-2.6/tkconch from 644 to 755
    changing mode of build/scripts-2.6/mailmail from 644 to 755
    changing mode of build/scripts-2.6/lore from 644 to 755
    changing mode of /tmp/myenv/bin/mktap to 755
    changing mode of /tmp/myenv/bin/ckeygen to 755
    changing mode of /tmp/myenv/bin/cftp to 755
    changing mode of /tmp/myenv/bin/conch to 755
    changing mode of /tmp/myenv/bin/tap2deb to 755
    changing mode of /tmp/myenv/bin/tap2rpm to 755
    changing mode of /tmp/myenv/bin/lore to 755
    changing mode of /tmp/myenv/bin/trial to 755
    changing mode of /tmp/myenv/bin/pyhtmlizer to 755
    changing mode of /tmp/myenv/bin/tkconch to 755
    changing mode of /tmp/myenv/bin/tapconvert to 755
    changing mode of /tmp/myenv/bin/manhole to 755
    changing mode of /tmp/myenv/bin/twistd to 755
    changing mode of /tmp/myenv/bin/mailmail to 755
  Running setup.py develop for django-contact-form
    Creating /tmp/myenv/lib/python2.6/site-packages/django-contact-form.egg-link (link to .)
    Adding django-contact-form 0.3 to easy-install.pth file
    
    Installed /tmp/myenv/src/django-contact-form
  Running setup.py develop for akismet
    Creating /tmp/myenv/lib/python2.6/site-packages/akismet.egg-link (link to .)
    Adding akismet 0.1.5 to easy-install.pth file
    
    Installed /tmp/myenv/src/akismet
  Running setup.py install for Fabric
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no files found matching 'fabfile.py'
    Installing fab script to /tmp/myenv/bin
  Running setup.py install for BeautifulSoup
  Running setup.py install for django-tagging
  Running setup.py install for zope.interface
    building 'zope.interface._zope_interface_coptimizations' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c src/zope/interface/_zope_interface_coptimizations.c -o build/temp.linux-x86_64-2.6/src/zope/interface/_zope_interface_coptimizations.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/zope/interface/_zope_interface_coptimizations.o -o build/lib.linux-x86_64-2.6/zope/interface/_zope_interface_coptimizations.so
    Skipping installation of /tmp/myenv/lib/python2.6/site-packages/zope/__init__.py (namespace package)
    Installing /tmp/myenv/lib/python2.6/site-packages/zope.interface-3.8.0-py2.6-nspkg.pth
  Running setup.py install for ssh
  Running setup.py install for pycrypto
    checking for gcc... gcc
    checking whether the C compiler works... yes
    checking for C compiler default output file name... a.out
    checking for suffix of executables...
    checking whether we are cross compiling... no
    checking for suffix of object files... o
    checking whether we are using the GNU C compiler... yes
    checking whether gcc accepts -g... yes
    checking for gcc option to accept ISO C89... none needed
    checking for __gmpz_init in -lgmp... no
    checking for __gmpz_init in -lmpir... no
    checking whether mpz_powm is declared... no
    checking whether mpz_powm_sec is declared... no
    checking how to run the C preprocessor... gcc -E
    checking for grep that handles long lines and -e... /bin/grep
    checking for egrep... /bin/grep -E
    checking for ANSI C header files... yes
    checking for sys/types.h... yes
    checking for sys/stat.h... yes
    checking for stdlib.h... yes
    checking for string.h... yes
    checking for memory.h... yes
    checking for strings.h... yes
    checking for inttypes.h... yes
    checking for stdint.h... yes
    checking for unistd.h... yes
    checking for inttypes.h... (cached) yes
    checking limits.h usability... yes
    checking limits.h presence... yes
    checking for limits.h... yes
    checking stddef.h usability... yes
    checking stddef.h presence... yes
    checking for stddef.h... yes
    checking for stdint.h... (cached) yes
    checking for stdlib.h... (cached) yes
    checking for string.h... (cached) yes
    checking wchar.h usability... yes
    checking wchar.h presence... yes
    checking for wchar.h... yes
    checking for inline... inline
    checking for int16_t... yes
    checking for int32_t... yes
    checking for int64_t... yes
    checking for int8_t... yes
    checking for size_t... yes
    checking for uint16_t... yes
    checking for uint32_t... yes
    checking for uint64_t... yes
    checking for uint8_t... yes
    checking for stdlib.h... (cached) yes
    checking for GNU libc compatible malloc... yes
    checking for memmove... yes
    checking for memset... yes
    configure: creating ./config.status
    config.status: creating src/config.h
    warning: GMP or MPIR library not found; Not building Crypto.PublicKey._fastmath.
    building 'Crypto.Hash._MD2' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/MD2.c -o build/temp.linux-x86_64-2.6/src/MD2.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/MD2.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_MD2.so
    building 'Crypto.Hash._MD4' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/MD4.c -o build/temp.linux-x86_64-2.6/src/MD4.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/MD4.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_MD4.so
    building 'Crypto.Hash._SHA256' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/SHA256.c -o build/temp.linux-x86_64-2.6/src/SHA256.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/SHA256.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_SHA256.so
    building 'Crypto.Hash._SHA224' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/SHA224.c -o build/temp.linux-x86_64-2.6/src/SHA224.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/SHA224.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_SHA224.so
    building 'Crypto.Hash._SHA384' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/SHA384.c -o build/temp.linux-x86_64-2.6/src/SHA384.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/SHA384.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_SHA384.so
    building 'Crypto.Hash._SHA512' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/SHA512.c -o build/temp.linux-x86_64-2.6/src/SHA512.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/SHA512.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_SHA512.so
    building 'Crypto.Hash._RIPEMD160' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -DPCT_LITTLE_ENDIAN=1 -Isrc/ -I/usr/include/python2.6 -c src/RIPEMD160.c -o build/temp.linux-x86_64-2.6/src/RIPEMD160.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/RIPEMD160.o -o build/lib.linux-x86_64-2.6/Crypto/Hash/_RIPEMD160.so
    building 'Crypto.Cipher.AES' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/AES.c -o build/temp.linux-x86_64-2.6/src/AES.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/AES.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/AES.so
    building 'Crypto.Cipher.ARC2' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/ARC2.c -o build/temp.linux-x86_64-2.6/src/ARC2.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/ARC2.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/ARC2.so
    building 'Crypto.Cipher.Blowfish' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/Blowfish.c -o build/temp.linux-x86_64-2.6/src/Blowfish.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/Blowfish.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/Blowfish.so
    building 'Crypto.Cipher.CAST' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/CAST.c -o build/temp.linux-x86_64-2.6/src/CAST.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/CAST.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/CAST.so
    building 'Crypto.Cipher.DES' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -Isrc/libtom/ -I/usr/include/python2.6 -c src/DES.c -o build/temp.linux-x86_64-2.6/src/DES.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/DES.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/DES.so
    building 'Crypto.Cipher.DES3' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -Isrc/libtom/ -I/usr/include/python2.6 -c src/DES3.c -o build/temp.linux-x86_64-2.6/src/DES3.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/DES3.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/DES3.so
    building 'Crypto.Cipher.ARC4' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/ARC4.c -o build/temp.linux-x86_64-2.6/src/ARC4.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/ARC4.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/ARC4.so
    building 'Crypto.Cipher.XOR' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/XOR.c -o build/temp.linux-x86_64-2.6/src/XOR.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/XOR.o -o build/lib.linux-x86_64-2.6/Crypto/Cipher/XOR.so
    building 'Crypto.Util.strxor' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/strxor.c -o build/temp.linux-x86_64-2.6/src/strxor.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/strxor.o -o build/lib.linux-x86_64-2.6/Crypto/Util/strxor.so
    building 'Crypto.Util._counter' extension
    gcc -pthread -fno-strict-aliasing -fwrapv -Wall -Wstrict-prototypes -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.6 -c src/_counter.c -o build/temp.linux-x86_64-2.6/src/_counter.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/src/_counter.o -o build/lib.linux-x86_64-2.6/Crypto/Util/_counter.so
Successfully installed psycopg2 Django Markdown Pygments Twisted django-contact-form akismet Fabric BeautifulSoup django-tagging zope.interface ssh pycrypto
Cleaning up...

Use virtualenv with Django and mod_python

Here is how to use a virtualenv with mod_python. This is taken from Django, mod_python and virtualenv. For more information, see the virtualenv documentation on using virtualenv without bin/python.

  • Create a file /srv/SaltyCrane/myvirtualdjango.py:
    activate_this = "/srv/python-environments/saltycrane/bin/activate_this.py"
    execfile(activate_this, dict(__file__=activate_this))
    
    from django.core.handlers.modpython import handler
    
  • Edit your httpd.conf
        <Location "/">
            SetHandler python-program
            PythonHandler myvirtualdjango
            SetEnv DJANGO_SETTINGS_MODULE iwiwdsmi.settings
            PythonPath "['/srv/SaltyCrane',] + sys.path"
            PythonDebug Off
        </Location>

Use virtualenv with Django and mod_wsgi

Added 2009-09-27: Here is how I set up my virtualenv with mod_wsgi. To use the the packages in my virtualenv, I used site.addsitedir at the top of my .wsgi application file. You may also want to set the WSGIPythonHome variable in your httpd.conf file (outside of any VirtualHost sections). For detailed information on using mod_wsgi with virtualenv, see the Virtual Environments section of the modwsgi project documentation.

  • /srv/SaltyCrane/saltycrane.wsgi:
    import os
    import sys
    import site
    
    site.addsitedir('/srv/python-environments/saltycrane/lib/python2.5/site-packages')
    
    os.environ['DJANGO_SETTINGS_MODULE'] = 'iwiwdsmi.settings'
    
    sys.path.append('/srv/SaltyCrane')
    
    import django.core.handlers.wsgi
    application = django.core.handlers.wsgi.WSGIHandler()
  • httpd.conf:
        WSGIScriptAlias / /srv/SaltyCrane/saltycrane.wsgi

Background / Discussion

Below are some links to some essential information on pip, virtualenv, and Python packaging (mostly from the creator of pip and virtualenv, Ian Bicking) and some further discussion on the state of Python packaging. (Updated 2012-11-17)

Converting time zones for datetime objects in Python

Install pytz

I am using pytz, which is a time zone definitions package. You can install it using Easy Install. On Ubuntu, do this:

sudo easy_install --upgrade pytz

Add time zone information to a naive datetime object

from datetime import datetime
from pytz import timezone

date_str = "2009-05-05 22:28:15"
datetime_obj = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
datetime_obj_utc = datetime_obj.replace(tzinfo=timezone('UTC'))
print datetime_obj_utc.strftime("%Y-%m-%d %H:%M:%S %Z%z")

Results:

2009-05-05 22:28:15 UTC+0000

Add non-UTC time zone information to a naive datetime object

(Added 2014-05-28)

NOTE: datetime.replace() does not handle daylight savings time correctly. The correct way is to use timezone.localize() instead. Using datetime.replace() is OK when working with UTC as shown above because it does not have daylight savings time transitions to deal with. See the pytz documentation.

from datetime import datetime
from pytz import timezone

date_str = "2014-05-28 22:28:15"
datetime_obj_naive = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")

# Wrong way!
datetime_obj_pacific = datetime_obj_naive.replace(tzinfo=timezone('US/Pacific'))
print datetime_obj_pacific.strftime("%Y-%m-%d %H:%M:%S %Z%z")

# Right way!
datetime_obj_pacific = timezone('US/Pacific').localize(datetime_obj_naive)
print datetime_obj_pacific.strftime("%Y-%m-%d %H:%M:%S %Z%z")

Results:

2014-05-28 22:28:15 PST-0800
2014-05-28 22:28:15 PDT-0700

Convert time zones

from datetime import datetime
from pytz import timezone

fmt = "%Y-%m-%d %H:%M:%S %Z%z"

# Current time in UTC
now_utc = datetime.now(timezone('UTC'))
print now_utc.strftime(fmt)

# Convert to US/Pacific time zone
now_pacific = now_utc.astimezone(timezone('US/Pacific'))
print now_pacific.strftime(fmt)

# Convert to Europe/Berlin time zone
now_berlin = now_pacific.astimezone(timezone('Europe/Berlin'))
print now_berlin.strftime(fmt)

Results:

2009-05-06 03:09:49 UTC+0000
2009-05-05 20:09:49 PDT-0700
2009-05-06 05:09:49 CEST+0200

List time zones

There are 559 time zones included in pytz. Here's how to print the US time zones:

from pytz import all_timezones

print len(all_timezones)
for zone in all_timezones:
    if 'US' in zone:
        print zone

Results:

US/Alaska
US/Aleutian
US/Arizona
US/Central
US/East-Indiana
US/Eastern
US/Hawaii
US/Indiana-Starke
US/Michigan
US/Mountain
US/Pacific
US/Pacific-New
US/Samoa

See also:

Notes on using nginx with mod_python and Django

Here are my notes on setting up nginx as a reverse proxy with Apache, mod_python, and Django on Ubuntu Intrepid. Nginx is used to serve my static media files while all other requests are passed on to the Apache/mod_python/Django web server.

I realize mod_wsgi has become the preferred way to deploy Django, but I'm a little behind the times and am still using mod_python. I hope to switch to mod_wsgi soon.

I have been using Amazon's CloudFront service for delivering my static media files. As far as I can tell, it has worked well. My main reason for switching to nginx is so I can skip the extra step of uploading to Amazon. Regarding my concern about the memory footprint of nginx, it looks like it is using around 5mb with my two process configuration.

My configuration parameters are shown below. I'm running two sites, SaltyCrane and HandsOnCards on a Slicehost 256mb plan.

DescriptionHandsOnCardsSaltyCrane
Redirectionhttp://www.handsoncards.com is redirected to http://handsoncards.comhttp://saltycrane.com is redirected to http://www.saltycrane.com
Static media filesystem path/srv/HandsOnCards/handsoncards/static//srv/SaltyCrane/iwiwdsmi/media/
Static media web path/site_media//site_media/
Django settings.py file location/srv/HandsOnCards/handsoncards/settings.py/srv/SaltyCrane/iwiwdsmi/settings.py
Additional Python packages path/srv/python-packages/srv/python-packages

Install nginx

Some recommend installing nginx from source, but I took the easier route and used Ubuntu's package manager.

sudo apt-get install nginx

Nginx configuration

Edit /etc/nginx/nginx.conf:

user www-data www-data;
worker_processes  2;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    access_log  /var/log/nginx/access.log;

    sendfile        on;
    tcp_nopush      on;

    keepalive_timeout  3;
    tcp_nodelay        off;

    gzip  on;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_types      text/plain text/html text/css application/x-javascript text/xml
                    application/xml application/xml+rss text/javascript;

    server {
        listen 80;
        server_name  www.handsoncards.com;
        rewrite ^/(.*) http://handsoncards.com/$1 permanent;
    }
    server {
        listen 80;
        server_name handsoncards.com;
      
        access_log /var/log/nginx/handsoncards.com.access.log;
        error_log /var/log/nginx/handsoncards.com.error.log;
      
        location / {
            proxy_pass http://127.0.0.1:8080/;
            include /etc/nginx/proxy.conf;
        }
        location /site_media/ {
            alias /srv/HandsOnCards/handsoncards/static/;
            expires 24h;
        }
    }
    server {
        listen 80;
        server_name saltycrane.com;
        rewrite ^/(.*) http://www.saltycrane.com/$1 permanent;
    }
    server {
        listen 80;
        server_name www.saltycrane.com;
      
        access_log /var/log/nginx/saltycrane.com.access.log;
        error_log /var/log/nginx/saltycrane.com.error.log;
      
        location / {
            proxy_pass http://127.0.0.1:8080/;
            include /etc/nginx/proxy.conf;
        }
        location /site_media/ {
            alias /srv/SaltyCrane/iwidsmi/media/;
            expires 24h;
        }
    }
}

Edit /etc/nginx/proxy.conf:

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;

Restart Nginx

sudo /etc/init.d/nginx restart

Install Apache

I already had Apache and mod_python installed, but in case you don't:

apt-get install apache2 apache2-mpm-prefork
apt-get install libapache2-mod-python

Apache Configuration

Edit /etc/apache2/httpd.conf:

MaxClients 2
MaxRequestsPerChild 350
KeepAlive Off
NameVirtualHost 127.0.0.1:8080
Listen 8080

<VirtualHost 127.0.0.1:8080>
    ServerName www.saltycrane.com
    <Location "/">
        SetHandler python-program
        PythonHandler django.core.handlers.modpython
        SetEnv DJANGO_SETTINGS_MODULE iwiwdsmi.settings
        PythonPath "['/srv/SaltyCrane', '/srv/python-packages'] + sys.path"
        PythonDebug Off
    </Location>
</VirtualHost>

<VirtualHost 127.0.0.1:8080>
    ServerName handsoncards.com
    <Location "/">
        SetHandler python-program
        PythonHandler django.core.handlers.modpython
        SetEnv DJANGO_SETTINGS_MODULE handsoncards.settings
        PythonPath "['/srv/HandsOnCards', '/srv/python-packages'] + sys.path"
        PythonDebug Off
    </Location>
</VirtualHost>

Edit /etc/apache2/ports.conf and comment out the following two lines:

#NameVirtualHost *:80
#Listen 80

Restart Apache

sudo /etc/init.d/apache2 restart

Add Django's reverse proxy middleware

Edit your settings.py file to include django.middleware.http.SetRemoteAddrFromForwardedFor in MIDDLEWARE_CLASSES. This allows your Django application to use the real IP address of the client instead of 127.0.0.1 from your nginx proxy. It sets Django's request.META['REMOTE_ADDR'] to be request.META['HTTP_X_FORWARDED_FOR'] which we set above in nginx's proxy.conf. For more information, see the Middleware reference in the Django documentation.

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.middleware.http.SetRemoteAddrFromForwardedFor',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
)

References

Errors

  • A 502 Bad Gateway from Nginx probably means there is something wrong with your Apache setup
  • An Internal Server Error from Apache means something is probably wrong with your Django setup.

How to reverse words in a sentence using Python and C

This is a technical problem I attempted recently. The problem was to reverse the words in a sentence. For example, The quick brown fox jumped over the lazy dog. becomes dog. lazy the over jumped fox brown quick The. I had to solve the problem first using Python, and then using C. In addition, the C version could only use 1 extra character of memory. I solved the Python version easily, but the C version was too difficult for me. Here are possible solutions.

Python version

sentence = "The quick brown fox jumped over the lazy dog."
words = sentence.split()
sentence_rev = " ".join(reversed(words))
print sentence_rev

C version

Credit for this solution goes to Hai Vu

#include <stdio.h>

/* function declarations */
void reverse_words(char *sentence);
void reverse_chars(char *left, char *right);

/* main program */
int main()
{
   char mysentence[] = "The quick brown fox jumped over the lazy dog.";

   reverse_words(mysentence);
   printf("%s\n", mysentence);

   return 0;
}

/* reverse the words in a sentence */
void reverse_words(char *sentence)
{
   char *start = sentence;
   char *end = sentence;

   /* find the end of the sentence */
   while (*end != '\0') {
      ++end;
   }
   --end;

   /* reverse the characters in the sentence */
   reverse_chars(start, end);
   
   /* reverse the characters in each word */
   while (*start != '\0') {
      /* move start pointer to the beginning of the next word */
      for (; *start != '\0' && *start == ' '; start++) ;

      /* move end pointer to the end of the next word */
      for (end=start; *end != '\0' && *end != ' '; end++) ;
      --end;

      /* reverse the characters in the word */
      reverse_chars(start, end);

      /* move to next word */
      start = ++end;
   }
}

/* reverse the characters in a string */
void reverse_chars(char *left, char *right)
{
   char temp;

   while( left < right) {
      temp = *left;
      *left = *right;
      *right = temp;
      ++left;
      --right;
   }
}

How to convert a PNM file to PDF with Python

  • Install the Python Imaging Library (PIL)
    On Ubuntu/Debian, use:
    sudo apt-get install python-imaging
  • Create a file called convert_pnm_to_pdf.py:
    import Image
    import os
    import sys
    
    filename = sys.argv[1]
    try:
        newfilename = os.path.splitext(filename)[0] + ".pdf"
        Image.open(filename).save(newfilename)
        print "Converted " + newfilename
    except IOError:
        print "Cannot convert" + newfilename
    
  • Run the script:
    python convert_pnm_to_pdf.py yourfile.pnm
    A PDF file named yourfile.pdf will be created

The PIL also supports many other file formats including BMP, GIF, JPEG, PNG, and TIFF. For more information, see the Python Imaging Library Handbook

My Python geek list

I noticed a few Python people had switched from Google Code to github or bitbucket. Then I thought, "Hey, maybe I can gather interesting information about my favorite Python geeks in a table!" Then I started making said table. Then I thought, "This is a dumb idea!" But I decided to post the table anyways. So, here it is: a dumb table of smart people.

BlogNetCodeViaOther
Adam Gomaatwitter iconbitbucketDjango People
Bob Ippolitotwitter iconGoogle Codesimplejson
David Beazlytwitter iconPython Essential Reference, Course on Coroutines, PLY
Glyph Lefkowitztwitter iconTwisted
Guido van Rossumtwitter iconGoogle CodePythonWikipedia
Ian Bickingtwitter iconbitbucketSQLObject, virtualenv, pip
Jack DiederichClass Decorators PyCon talk
Jacob Kaplan-Mosstwitter icongithubDjangoDjango People
James Bennetttwitter iconbitbucketDjangoDjango People
James Taubertwitter icongithubPinaxDjango People
Simon Willisontwitter iconGoogle Code, githubDjangoWikipedia
Django People

Scripting wmii column widths with Python

I mentioned in my previous post on using wmii with Gnome that I had written a script for resizing the column widths in wmii. This is the followup post. Note, I am using the 20080520 snapshot of wmii. This doesn't work with wmii 3.6 (as Marco commented below).

To incrementally change window sizes, I use the following in my ~/.wmii-3.5/wmiirc file:

	Key $MODKEY-y
		# shrink horizontally
		wmiir xwrite /tag/sel/ctl grow sel sel right -10
		wmiir xwrite /tag/sel/ctl grow sel sel left -10
	Key $MODKEY-u
		# grow horizontally
		wmiir xwrite /tag/sel/ctl grow sel sel right 10
		wmiir xwrite /tag/sel/ctl grow sel sel left 10
	Key $MODKEY-i
		# shrink vertically
		wmiir xwrite /tag/sel/ctl grow sel sel down -10
		wmiir xwrite /tag/sel/ctl grow sel sel up -10
	Key $MODKEY-o
		# grow vertically
		wmiir xwrite /tag/sel/ctl grow sel sel down 10
		wmiir xwrite /tag/sel/ctl grow sel sel up 10
	Key $MODKEY-Shift-y
		# shrink horizontally
		wmiir xwrite /tag/sel/ctl grow sel sel right -2
		wmiir xwrite /tag/sel/ctl grow sel sel left -2
	Key $MODKEY-Shift-u
		# grow horizontally
		wmiir xwrite /tag/sel/ctl grow sel sel right 2
		wmiir xwrite /tag/sel/ctl grow sel sel left 2
	Key $MODKEY-Shift-i
		# shrink vertically
		wmiir xwrite /tag/sel/ctl grow sel sel down -2
		wmiir xwrite /tag/sel/ctl grow sel sel up -2
	Key $MODKEY-Shift-o
		# grow vertically
		wmiir xwrite /tag/sel/ctl grow sel sel down 2
		wmiir xwrite /tag/sel/ctl grow sel sel up 2

In addition to incrementally changing column widths, I wanted to be able to switch to predetermined column width ratios with a keyboard shortcut. For example, I wanted to be able to set the column widths at a 20/80 ratio, a 40/60 ratio, a 50/50 ratio, a 60/40 ratio, and so on. So I hacked a Python script to do this. It is pretty ugly because I first grow the window by a set amount, measure the change in size, then grow it again to the correct width. If anyone knows of a better way to do this, please let me know. I'm posting my solution here in case anyone else wanted to do the same thing and got stuck. (Note, this script only works with two columns)

UPDATE 2009-12-21: I just learned from the new wmii documentation that I can specify a grow amount in pixels by suffixing it with "px". This means I no longer have to perform the ugly, extra grow-then-measure step in my script. I'm not sure if this is a newly added change or if it is just newly documented. I am now using wmii 3.9b1. I have updated the script below to use the new method. Also, the script now works with more than two columns. I kept the old method for reference.

#!/usr/bin/env python

import os
import re
import sys

class Wmii:
    """
    wmiir xwrite /tag/sel/ctl grow col row side increment
    col: column number of the window to grow
    row: row number of the window to grow
    side: the side to grow. one of left, right, up, or down
    increment: the number of pixels to grow. use a positive number to grow larger
    and a negative number to grow smaller
    """
    def set_column_widths(self, width_list):
        """Use the 'grow' command to set the column widths to those specified.
        Widths are specified in percentages.
        """
        total_width_perc = sum([float(width) for width in width_list])
        for i, width_perc in enumerate(width_list[:-1]):
            self.read_current_col_widths()
            total_width_px = float(sum(self.curr_colwidths))
            new_width_px =  float(width_perc) / total_width_perc * total_width_px
            grow_amount_px = int(round(new_width_px - self.curr_colwidths[i]))
            self.xwrite("/tag/sel/ctl grow %d 1 right %dpx" % (i+1, grow_amount_px))

    def read_current_col_widths(self):
        """'wmiir read /tag/sel/index' and set the attribute, self.curr_colwidths.
        self.curr_colwidths is a list of the width (ints) (in pixels) of each
        column in the view.
        """
        lines = self.read("/tag/sel/index")
        self.curr_colwidths = []
        for line in lines:
            match = re.search(r"# [^~]+ \d+ (\d+)", line)
            if match:
                self.curr_colwidths.append(int(match.group(1)))
        print self.curr_colwidths

    def xwrite(self, path_and_value):
        """Use the xwrite form."""
        cmd = "wmiir xwrite %s" % path_and_value
        print cmd
        os.system(cmd)

    def read(self, path):
        """Return a list of the lines returned by "wmii read path" """
        return os.popen4("wmiir read " + path)[1].readlines()

if __name__ == "__main__":
    w = Wmii()
    w.set_column_widths(sys.argv[1:])
Old method (for reference):
#!/usr/bin/env python

import os
import re
import sys

class Wmii:
    """
    wmiir xwrite /tag/sel/ctl grow col row side increment
    col: column number of the window to grow
    row: row number of the window to grow
    side: the side to grow. one of left, right, up, or down
    increment: the number of pixels to grow. use a positive number to grow larger
    and a negative number to grow smaller
    """
    def __init__(self):
        pass

    def set_column_widths(self, width0, width1):
        """Use the 'grow' command to set the column widths to those specified.
        Widths are specified in percentages.
        Currently only works with 2 columns.
        """
        self.determine_pixels_per_grow_horiz()
        new_width0 = sum(self.curr_colwidths) * (float(width0) /
                                                 (float(width0)+float(width1)))
        grow_amount = int(round((new_width0-self.curr_colwidths[0]) /
                                self.pixels_per_grow_increment))
        self.xwrite("/tag/sel/ctl grow 1 1 right %d" % grow_amount)

    def determine_pixels_per_grow_horiz(self):
        """Try growing by an increment of 1 and record the number of pixels changed.
        """
        self.read_current_col_widths()
        prev_colwidth0 = self.curr_colwidths[0]
        self.xwrite("/tag/sel/ctl grow 1 1 right 1")
        self.read_current_col_widths()
        self.pixels_per_grow_increment = self.curr_colwidths[0] - prev_colwidth0

    def read_current_col_widths(self):
        """'wmiir read /tag/sel/index' and set the attribute, self.curr_colwidths.
        self.curr_colwidths is a list of the width (ints) (in pixels) of each
        column in the view.
        """
        lines = self.read("/tag/sel/index")
        self.curr_colwidths = []
        for line in lines:
            match = re.search(r"# [^~]+ \d+ (\d+)", line)
            if match:
                self.curr_colwidths.append(int(match.group(1)))
        print self.curr_colwidths

    def read_current_column_number(self):
        """'wmiir read /tag/sel/ctl' and set the attribute, self.curr_col."""
        lines = self.read("/tag/sel/ctl")
        self.curr_col = re.split(" ", lines[1])[1]
        print "curr_col = %s" % self.curr_col

    def xwrite(self, path_and_value):
        """Use the xwrite form."""
        cmd = "wmiir xwrite %s" % path_and_value
        print cmd
        os.system(cmd)

    def read(self, path):
        """Return a list of the lines returned by "wmii read path" """
        return os.popen4("wmiir read " + path)[1].readlines()

if __name__ == "__main__":
    w = Wmii()
    w.set_column_widths(sys.argv[1], sys.argv[2])

I named the script wmii.py, made it executable, and put it on my path. Then I modified my wmiirc:

	Key $MODKEY-q
		wmii.py 20 80
	Key $MODKEY-w
		wmii.py 40 60
	Key $MODKEY-e
		wmii.py 50 50
	Key $MODKEY-r
		wmii.py 60 40
	Key $MODKEY-t
		wmii.py 80 20

Hope that's helpful to someone. Let me know if you've written some cool python wmii scripts.

Consolidating hostings services

I've been using Webfaction shared hosting for this blog and Slicehost VPS hosting for our greeting card store. I've had no problems with Webfaction, but I'd like to put both sites on one host, so I am moving this blog to Slicehost. Later, I might switch from Slicehost to Linode because they seem to have lower prices than Slicehost. But I thought I'll do one step at a time. I've already moved my code over and everything seems to be working OK. I plan to switch the nameservers soon after I put this post up. If any comments are posted during the switch, they might get lost. My domain registrar says it might take ~48 hours to be complete. I'm not sure exactly how that works. I will change the footer at the bottom of the Slicehost-hosted site to read "Hosted by Slicehost" while the Webfaction site will continue to read "Hosted by Webfaction".

Update 2009-06-22: Here is an endorsement for Slicehost by James Bennett (and many more in the comments). Maybe I should rethink a switch to Linode.