Installing Python 3.0 Alongside an Existing Python

With the recent release of Python 3.0 final, I've had a crazy itch that needed to be scratched. That itch, my friends, was to do a write-up of how to install Python 3.0 alongside my existing Python 2.5.2 installation without borking things up. The reason I thought it would be useful is that I'm running a Debian-based distribution of Linux called sidux right now, and neither Python 2.6 nor Python 3.0 are in the package repositories. I assume that Ubuntu and other Debian-based distributions might be the same way, and that there are others like me who would like to tinker with these new releases.

Just before attempting to install Python 3.0 on my computer, I started getting ready to write this article. Before I knew it, Python 3.0 was installed on my system, and I had no notes to share with you! That is how stinkin easy it is to install Python 3.0 without interfering with an existing install. I mentioned to a good friend that I wasn't sure the process was worth writing an article because it was so simple, but he encouraged me to carry on. Thanks bro.

So, without any further ado, here is what I did to install Python 3.0 from source alongside my Python 2.5 installation:

Note: If you're using a Mac or Windows, you should be able to simply install the packages for your platform to accomplish this same feat. Once the packages are in the repositories it will be just as easy for Linux.

$ wget http://python.org/ftp/python/3.0/Python-3.0.tar.bz2
  • Unpack the archive:
$ tar jxf Python-3.0.tar.bz2
  • Descend into the newly extracted Python-3.0 directory:
$ cd Python-3.0
  • Install libreadline-dev. This step is necessary for the arrow keys to work, as pointed out by jazevec below in the comments. If you are on a Debian-based system, you can execute a command such as this:
  $ sudo apt-get install libreadline-dev

Other distributions may have different package names, such as ``readline-dev``.  If neither one of those package names work for your distribution, try searching your package manager for ``readline`` and install the development files.  Alternatively, you should be able to manually install what you need by installing `readline itself <http://directory.fsf.org/project/readline/>`_.
  • Configure Python 3.0 for your computer:
$ ./configure
  • Compile Python 3.0:
  $ make


**UPDATE** (9 Dec): Depending on your setup, you may or may not see a message such as this after executing the ``make`` command (thanks again to ``jazevec`` for pointing out that this can happen)::

  Failed to find the necessary bits to build these modules:
  _dbm               _gdbm              _hashlib
  _sqlite3           _ssl               _tkinter
  bz2                zlib
  To find the necessary bits, look in setup.py in detect_modules() for the module's name.

If you need any of those capabilities, you should install the appropriate development files for the missing module(s).  For example, above, we installed the ``libreadline-dev`` package.  To resolve the missing module problem for each one listed above (except ``_dbm`` because it's apparently borked on Debian right now... possibly other distros too), install these packages:

  * ``tk-dev`` to satisfy ``_tkinter``
  * ``libsqlite3-dev`` to satisfy ``_sqlite3``
  * ``libbz2-dev`` to satisfy ``bz2``
  * ``zlib1g-dev`` to satisfy ``zlib``
  * ``libssl-dev`` to satisfy ``_ssl`` and ``_hashlib``
  * ``libgdbm-dev`` to satisfy ``_gdbm``
  • Install Python 3.0:
  $ sudo make install

or:
# make install
  • Test Python 3.0:
$ python3.0
Python 3.0 (r30:67503, Dec  5 2008, 11:05:45)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'Hi'
File "<stdin>", line 1
    print 'Hi'
            ^
SyntaxError: invalid syntax
>>> print('Hi')
Hi
>>>
  • Make sure that your old version of Python is still around:
$ python
Python 2.5.2 (r252:60911, Sep 29 2008, 21:15:13)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'Hi'
Hi
>>>
  • Rejoice

That's about it folks! Extremely simple and fast, compared to what it could have been.

If you find yourself in a situation where you don't have access to sudo or straight root-level access, you can install Python 3.0 locally by doing something like this:

  • Configure Python 3.0 for your computer:
$ ./configure --prefix=$HOME/local/
  • Compile Python 3.0:
$ make
  • Install Python 3.0:
  $ make install

Not that I omitted the ``sudo`` part of the command here.
  • Symlink to Python 3.0, assuming you have a bin/ directory in your home directory (i.e. /home/[yourusername]/bin), and that said bin directory is on your PATH:
$ ln -s ~/local/bin/python3.0 ~/bin
  • Test your locally installed Python 3.0:
  $ python3.0

or, if your local ``bin`` directory isn't on your ``PATH``:
$ ~/bin/python3.0
  • Do the dance.

Please comment with any problems you find with this process, or any additional advice you can offer to newbies!

django-watermark 0.1.5-pre1

I've been making several updates to django-watermark during my more boring classes the past couple days. I have just released a new version for your pleasure.

Changes include:

  • A lot of code refactoring. There was a lot of logic in the watermark filter itself. I decided this logic should be placed elsewhere so as to make the utils.watermark function easier to use outside the realm of the watermark filter.
  • Removed the "parameter precedence" that used to exist between the positioning, tiling, and scaling parameters. Previously, if scale was defined, any values for position and tile were ignored. Similarly, if any value was given for tile, any value for position was ignored. Now you can use all three parameters simultaneously.
  • Added a couple of goodies for positioning and scaling.

I think this is quite a stable release. Please notify me if you find any problems with it!!

django-watermark 0.1.2-pre1

I've added a few updates to django-watermark and figured it was time to announce another release. Updates include:

  • the ability to place watermarks randomly on the target image
  • updated the way relative positioning works. Now, position=50%x50% will center the watermark image on the target image. Previously django-watermark placed the top-left corner of the watermark image in the center of the target image.
  • the ability to convert the watermark image to a transparent greyscale image before applying it to the target image
  • the ability to rotate the watermark image using either a specific number of degrees or usign a random rotation value

Both Google Code and PyPI have been updated with these changes.

New Comment Notification by E-mail

This little trick certainly isn't anything special. Several other folks have posted about how to have Django send out an e-mail automagically when a new comment has been posted on your site. However, a lot of these other posts seem to be pre-Django 1.0. Some groovy changes took place with the signal system slightly before Django 1.0 was released, so I thought I'd share my method of having Django notify me by e-mail when someone posts a comment on my sites.

My code follows:

from django.db.models.signals import post_save
from django.core.mail import mail_admins
from django.contrib.comments.models import Comment

def notify_of_comment(sender, instance, **kwargs):
    message = 'A new comment has been posted.\n'
    message += instance.get_as_text()

    mail_admins('New Comment', message)

post_save.connect(notify_of_comment, sender=Comment)

Nice and simple, right? Right. All this does is it creates a callback function called notify_of_comment and waits for Django to signal that a Comment object has been saved. Any time that signal is intercepted, the callback will send off an e-mail to anyone in the settings.ADMINS list.

You should be able to put such code anywhere in your project so long as that anywhere is loaded when your project starts up. I usually put signal interceptors in an __init__.py file somewhere, though they should work just as well in a models.py or urls.py file.

I realize that the django-comment-utils project is capable of notifying when a comment has been posted, but I didn't want much else from the project. That is why I did it this way ;)

Adding Captcha To Django's Built-in Comments

I recently had a good friend of mine ask for some help in adding a captcha field to his comments form. I gave him some pointers, but before he could put them into action he had to leave for a Thanksgiving roadtrip home. I didn't give much mind to the idea of putting captchas on my own site since it's not all that popular amongst spammers yet. When I woke up this morning, however, I found myself with a few spare minutes to see if my pointers were correct.

Some of the ideas I shared with my friend turned out to not work very well. As I tinkered about trying to get things to work on my own site, I think I came up with a relatively efficient way of doing things.

Installing The Captcha

The captcha field I use is quite simple and effective. I originally got it from http://django.agami.at/media/captcha/, but the project seems to be unmaintained now. Along the road to Django 1.0, some changes were made to the way form fields work, and there is a minor change required in the base code for this captcha field if you want it to work. Alternatively, you can use a copy of the field that I'm currently using.

All you need to do is extract the captcha directory somewhere on your PYTHONPATH. The author recommends putting it in django.contrib, but I usually just place it straight on the PYTHONPATH so all I need to do is from captcha import CaptchaField instead of from django.contrib.captcha import CaptchaField. Minor details...

Adding The Captcha

The first thing you'll want to do after installing the captcha field is add the field itself to your comments form. Instead of subclassing the built-in django.contrib.comments.forms.CommentForm form, I simply decorated the constructor of the form as such:

1
2
3
4
5
6
7
8
9
from django.contrib.comments.forms import CommentForm
from captcha import CaptchaField

def add_captcha(func):
    def wrapped(self, *args, **kwargs):
        func(self, *args, **kwargs)
        self.fields['security_code'] = CaptchaField()
    return wrapped
CommentForm.__init__ = add_captcha(CommentForm.__init__)

This adds a field called security_code to the CommentForm, and it works the same way as if you had done something like this:

1
2
3
4
5
6
7
from django import forms
from captcha import CaptchaField

class MyCommentForm(forms.Form):
    name = forms.CharField()
    ...
    security_code = CaptchaField()

You can put the decorating snippet from above anywhere you'd like so long as the module you put it in is loaded at some point in your project. I usually put this sort of magic in my main urls.py file so it's harder to forget about when I debug things.

Fixing the Form

The first problem with this little trick seems to be that the CaptchaField is rendered as unsafe HTML in the default form.html template in the built-in comments application. That just means that, instead of seeing the captcha, you will see the HTML necessary to render the CaptchaField directly on the page, like this:

<input type="hidden" name="security_code" value="captcha.caZ1SqQ" />
<img src="/static/captchas/caZ1SqQ/0656f09d3974850397dd4c4974f23a35.gif"
 alt="" /><br /><input type="text" name="security_code"
 id="id_security_code" />

To fix that, you can apply the safe filter to the field and make the template look something like this:

{% load comments i18n %}
<form action="{% comment_form_target %}" method="post">
<table>
{% for field in form %}
    {% if field.is_hidden %}
    {{ field }}
    {% else %}
    <tr{% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}>
        <th>{{ field.label_tag }}:</th>
        <td {% if field.errors %} class="error"{% endif %}>
            {{ field|safe }} &nbsp;
            {% if field.errors %}{{ field.errors|join:"; " }}{% endif %}
        </td>
    </tr>
    {% endif %}
{% endfor %}
</table>
<p class="submit">
    <input type="submit" name="post" class="submit-post"
     value="{% trans "Post" %}" />
    <input type="submit" name="preview" class="submit-preview"
     value="{% trans "Preview" %}" />

</form>

Notice the {{ field|safe }} in there. Also note that I prefer the table layout for the comment form over the default mode. If you change your form template as I have done, you should put the updated copy in your own project's template directory. It belongs in templates/comments/form.html, assuming that your templates directory is called templates. You'll probably also want to check out the preview.html template for the django.contrib.comments application. I changed mine to look like this:

{% extends "comments/base.html" %}
{% load i18n %}

{% block title %}{% trans "Preview your comment" %}{% endblock %}

{% block content %}
    {% load comments %}
    {% if form.errors %}
    <h1>{% blocktrans count form.errors|length as counter %}Please
     correct the error below{% plural %}Please correct the errors below
     {% endblocktrans %}</h1>
    {% else %}
    <h1>{% trans "Preview your comment" %}</h1>
        <blockquote>{{ comment|linebreaks }}</blockquote>

        {% trans "and" %} <input type="submit" name="submit"
         class="submit-post" value="{% trans "Post your comment" %}"
         id="submit" /> {% trans "or make changes" %}:

    {% endif %}

    {% include 'comments/form.html' %}
{% endblock %}

See how I just use the include tag to pull in the comments/form.html template I mentioned above? Saves a lot of typing and potential for problems... If you update the preview.html template, you should save your copy in templates/comments/preview.html, assuming your templates directory is called templates.

Testing It Out

At this point, you should be able to try out your newly installed captcha-fied comments. If it doesn't work, please comment on this article and perhaps we can figure out the problem!

Project Release: django-watermark 0.1.0-pre1

I've found myself in many situations where I have several images that need a watermark applied to them. Applying a watermark to more than 5 images at a time is annoying at best, even if you do have macros to do the mundane stuff for you. I don't like to do things that annoy me.

Recently, I found myself yet again confronted with a "please watermark these images" sort of situation, and I decided to take a more logical approach to the problem: program it. The result of my efforts is called django-watermark and is available on Google Code and PyPI. To be perfectly honest, I actually ganked most of the useful code for this application from a generous soul on the Internet.

This seems to be working fine for me. I think the positioning for watermarks might need more work, but there are several options to hold people over for the time being. Please let me know what your thoughts are.

ReStructured Text

I've been working on updating all of my articles to use ReStructured text formatting these past couple of days. Basically ever since I started using Django on my personal sites, I used Textile formatting to make my articles look pretty, and it treated me well. However, I found myself with a few extra minutes to do some research this weekend, and the topic I happened to research was the difference between ReStructured text, Markdown, and Textile.

After my brief research into these utilities, I decided it would be worth my while to convert all of my articles and other Textile-formatted content to use ReStructured text instead. Most of this is due to personal preferences for certain conventions--very little technical reasoning came into play when I made the decision to switch (so don't ask me why I abandoned one for the other if you expect a technical pro/con list). Suffice it to say that I consider the ReST syntax to be superior to that of Textile.

In the conversion process, I realized that I wrote a whole lot more in my articles than I thought I did! It took much longer than expected, but the work is done now, and all of the articles should be updated. Most of you probably won't be able to tell much of a difference one way or another, but if you do find a problem with the formatting of any of my articles, please notify me!

Project Release: django-reploc 0.1.0-pre1

Here's yet another application to help you make your site more useful to your users. django-reploc is a "representative locator" for Django-powered Web sites. It uses the Google Maps API to offer your users an interactive map of your representatives, vendors, friends, houses, etc.

I built this application to be a dealer locator for one of my clients. The application provides a way for you to create "representatives," and each representative may have one or more locations. For example, say you are a producer of clothing and apparel, ranging from shoes to pants to t-shirts to sweaters to hats to bags and so on. Perhaps your bigger representatives (or vendors) carry your products in all of their retail branches. reploc gives you a way to display each of these locations for the one vendor on a map for your users.

In addition to that, while the bigger vendors might carry your products in all locations, perhaps some locations only carry particular lines of your products. For example, a vendor location in Miami, Florida might carry a good deal of your sandals and none of your sweatshirts, while a vendor location in Bangor, Maine might not bother with any sandals but keeps sweatshirts in stock year-round. reploc offers a way for you to describe which product lines each location carries by the use of "attributes".

However, it can be used for much more than just that. Pretty much any location that you can show on Google Maps (is there anything that can't be shown on Google Maps anymore?) can be displayed with this application.

Furthermore, you can search for locations within a certain radius of an address that your users specify! A nice circle is drawn on the map, making it visually easier to understand what is and isn't within range. To make things even easier, the locations that do not fall within the radius of the given address are hidden from the map.

Finally, once a user finds a location within the radius of the address they specify, they are able to get driving directions to help them get right where they need to go!

w00t!

To learn more, go to the project page: http://code.google.com/p/django-reploc/

Setup a favicon.ico in Django

Up until a couple weeks ago, I had never installed a FavIcon on any of my Django sites. I never really thought about it until one day I enabled the SEND_BROKEN_LINK_EMAILS setting for one of my sites. As soon as I did that, I was able to track down links to broken pages very quickly. It also notified me that I didn't have a favicon.ico file setup anywhere on my site, and there are a great many programs out there that look for this file automatically.

At first I tried to go through Apache to get this working, but I'm no Apache guru so I was less than successful in taking this route. A couple of days ago I figured out a little trick to make the missing favicon.ico file stop sending me "broken link" e-mails hundreds of times a day. The solution? Put a favicon on my site, of course!

The approach I took was to simple add some information to my main urls.py file. Here's the line straight from my URLconf:

(r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}),

Hah! Simple isn't it? This way Apache is still handling the actual serving of the static image file--Django just handles the redirect. Ever since I added this line to my URLconf, I've not received one "broken link" e-mail pertaining to the missing favicon.ico file. That leads me to believe that most applications can understand the redirect and plug the actual image file where it belongs.

Oh, and for those of you who might be curious... My favicon.ico is actually just a PNG image that I renamed to favicon.ico. Again, most things seem to understand this (but I could be wrong).

See below for a more complete example of my URLconf

from django.conf.urls.defaults import *

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),
    (r'^robots\.txt$', 'django.views.generic.simple.direct_to_template', {'template': 'robots.txt', 'mimetype': 'text/plain'}),
    (r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}),
    (r'^$', 'django.views.generic.simple.direct_to_template', {'template': 'base_home.html'}),
)