Posts Tagged Python

PostgreSQL & Python on Mac

I’ve been playing with Django & MySQL for a while but for my next project I wanted to integrate it with a PostgreSQL database. Everything went well until I wanted to install Psycopg as my python adapter to PostgreSQL.

After a bit of blundering about here’s what it eventually took:

  • Download and install PostgreSQL one-click installer from http://www.postgresql.org/download/macosx. Remember to read the README file before actually running the installer.
  • Download the psycopg2 source from http://initd.org/pub/software/psycopg/.
  • Edit the setup.cfg file to provide a path to the pg_config executable. On my Mac it sits in /Library/PostgreSQL/8.4/bin/pg_config and is not by default on the PATH so if you don’t put it on the PATH or in this configuration file the next step will fail in a spectacular manner.
  • Run ‘sudo easy_install .‘ in the top level psycopg2 source directory.
  • Specify postgresql_psycopg2 when you configure Django’s database layer for your project.

Tags: , , ,

Django RESTful resources

Last year I blogged about a neat trick in Django to have multiple views per HTTP verb. Since then I’ve been playing with RESTful applications and decided to see if there was a nicer way to expose “resources” in Django. The following is what I’ve come up with so far.

Listing: router.py

from django.http import Http404, HttpResponseNotAllowed

def get_handler_method(request_handler, http_method):
    try:
        handler_method = getattr(request_handler, http_method.lower())
        if callable(handler_method):
            return handler_method
    except AttributeError:
        pass

class Resource:

    http_methods = ['GET', 'POST', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']

    @classmethod
    def dispatch(cls, request, *args, **kwargs):
        request_handler = cls()

        if request.method in cls.http_methods:
            handler_method = get_handler_method(request_handler, request.method)
            if handler_method:
                return handler_method(request, *args, **kwargs)

        methods = [method for method in cls.http_methods if get_handler_method(request_handler, method)]
        if len(methods) > 0:
            return HttpResponseNotAllowed(methods)
        else:
            raise Http404

Listing: views.py

from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from router import Resource
from models import Document
from django import forms
import identity

class DocumentForm(forms.Form):
    one = forms.CharField()
    two = forms.CharField()
    date = forms.CharField()

def index(request):
    document_links = []
    for document in Document.objects.all():
        url = reverse('document', args=[document.id])
        document_links.append({ 'identity': document.id, 'url': url })

    new_form_url = reverse('document', args=[identity.NEW])
    model = { 'document_links': document_links, 'new_form_url': new_form_url }
    return render_to_response('index.html', model)

def success(request, document_id):
    document = get_object_or_404(Document, pk=document_id)
    form = DocumentForm(document.get_values())
    form.is_valid()

    model = { 'form': form.cleaned_data, 'index_url': reverse('index') }
    return render_to_response('success.html', model)

class DocumentView(Resource):

    def get(self, request, document_id):
        if identity.is_new(document_id):
            form = DocumentForm()
        else:
            document = get_object_or_404(Document, pk=document_id)
            form = DocumentForm(document.get_values())

        model = { 'form': form, 'index_url': reverse('index') }
        return render_to_response('form.html', model)

    def post(self, request, document_id):
        if identity.is_new(document_id):
            document = Document()
        else:
            document = get_object_or_404(Document, pk=document_id)

        document.set_values(request.POST)
        document.save()

        form = DocumentForm(document.get_values())
        if form.is_valid():
            url = reverse('success', args=[document.id])
        else:
            url = reverse('document', args=[document.id])

        return HttpResponseRedirect(url)

Listing: urls.py

from django.conf.urls.defaults import *
from django.conf import settings
import os, views

urlpatterns = patterns('',
    url(r'^document/(?P<document_id>[A-Za-z0-9\-]+)/$', views.DocumentView.dispatch, name='document'),
    url(r'^success/(?P<document_id>[A-Za-z0-9\-]+)/$', views.success, name='success'),
    url(r'^$', views.index, name='index'),
)

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', 'django.views.static.serve',
            {'document_root': os.path.join(os.path.dirname(__file__), 'static')}),
    )

It does add a little bit more magic to the views (since you don’t actually see the dispatch method at all) but it benefits from simpler mapping in urls.py, as well as an easier way to figure out what instance method on a Resource subclass gets called for each HTTP verb. Never felt that comfortable with popping-off of kwargs in last year’s post.

Tags: , , , , ,

From Java to Groovy

Recently I’ve been playing with some old Java Swing applications and I found myself wishing that I could replace all the anonymous inner-classes with some clean Groovy closures. The job of converting a java source file to a groovy source file is pretty simple and eminently scriptable. Here’s my take on a python script to do just that:

from optparse import OptionParser
from subprocess import Popen, PIPE
import os

def rename(src, dest, use_svn):
    if use_svn:
        output = Popen(['svn', 'rename', src, dest], stdout=PIPE).communicate()
        print output[0]
    else:
        print 'mv', src, dest
        os.rename(src, dest)

def process_file(src, use_svn):
    if src.endswith('.java'):
        print 'Processing', src
        fd = open(src, 'r')
        lines = fd.readlines()
        fd.close()
        fd = open(src, 'w')
        for line in lines:
            text = line.rstrip()
            if text.endswith(';'):
                text = text[:-1]
            fd.write(text)
            fd.write('\n')
        fd.close()
        root = os.path.dirname(src)
        filename = os.path.basename(src)
        dest = os.path.join(root, filename[:-5] + '.groovy')
        rename(src, dest, use_svn)

def process_dir(dir_path, use_svn):
    for root, dirs, files in os.walk(dir_path):
        for filename in files:
            src = os.path.join(root, filename)
            process_file(src, use_svn)

if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option('-s', '--svn', action='store_true', dest='use_svn', help='use svn to rename files')
    (options, args) = parser.parse_args()
    if len(args) > 0:
        target = args[0]
        if os.path.isfile(target):
            process_file(target, options.use_svn)
        else:
            process_dir(target, options.use_svn)
    else:
        process_dir(os.getcwd(), options.use_svn)

This means that I can now replace this:

public void actionPerformed(ActionEvent e) {
    executor.execute(new Runnable() {
        public void run() {
            controller.showBuckets();
        }
    });
}

with this:

public void actionPerformed(ActionEvent e) {
    executor.execute { controller.showBuckets() }
}

Now that’s refactoring ;-)

Tags: , , , ,