Archives

February 2010 (1)
September 2009 (1)
May 2009 (1)
April 2009 (1)
March 2009 (4)
January 2009 (3)

November 2008 (2)
October 2008 (2)
September 2008 (1)
August 2008 (5)
July 2008 (3)
June 2008 (1)
May 2008 (5)
April 2008 (8)
March 2008 (3)
February 2008 (1)
January 2008 (2)

December 2007 (2)
November 2007 (4)
October 2007 (17)
September 2007 (9)

Ian Bicking, Paste, WebOb and WSGI

Wednesday, April 30 2008

Ian Bicking has updated his simple WSGI tutorial to use his new WebOb package. The software running this blog, Burble, owes everything to Ian’s tutorial (in its old version) and the accompanying parts of his Paste project. It is because of these and the simplicity of the WSGI spec that you can have a working Python application server in a few lines.

There are rich pickings in Ian’s blog if you are interested in Python or in web development, or programming in general.

no comments

Tags: ian bicking ~ wsgi

A tiny WSGI framework in an hour or two

Sunday, October 14 2007

 I’m not sure whether the first story here is meant to encourage or dissuade, but I am writing my own WSGI framework to support Burble. Colubrid is holding me back, and its replacement Werkzeug is overkill for what I want. (To be fair, Colubrid has been a great help to me in getting started.) I’m really getting into the educational aspect of doing things from scratch where I can.

It turns out that putting together a very lightweight WSGI framework is very easy indeed, especially having made a small compromise by using a few pre-built things from Ian Bicking’s Paste. (Yeah, I contradict myself. I am large, I contain multitudes.)

It’s so easy that I’m almost done, so I present a tiny, noddy framework for your reading pleasure. It implements a regex-based URL dispatcher a la Web.py.


#!/usr/bin/python
from paste.request import parse_formvars
from paste.response import HeaderDict
import re

def attrsfromdict(d):
"""From Python cookbook s6.18 p 280"""
self = d.pop('self')
for n,v in d.iteritems():
setattr(self, n, v)

def simplerepr(obj):
d = obj.__dict__
members = ', '.join([n + '=' + v.__repr__() for n,v in d.iteritems()])
return '%s(%s)' % (obj.__class__.__name__, members)

class NoMatchingControllerException(Exception):
pass

class Request(object):
def __init__(self, environ):
self.environ = environ
self.fields = parse_formvars(environ)

class Response(object):
def __init__(self,
status_code='200',
response_phrase="OK", body="",
headers=HeaderDict({'content-type': 'text/html'})
):
attrsfromdict(locals())
def __str__(self):
return simplerepr(self)
def __repr__(self):
return self.__str__()
def status(self):
return ' '.join([self.status_code, self.response_phrase])

class Dispatcher(object):
"""
The Dispatcher maintains an internal list of regexes and controllers.
The Dispatcher accepts strings, and tries to match in turn against
the regexes. As soon as a match is found, the corresponding controller is
invoked.
"""
def __init__(self, regex_app_tuples):
self.dispatch_list = []
for k, v in regex_app_tuples:
p = re.compile(k)
self.dispatch_list.append((p, v))

def dispatch(self, request):
"""
Expects to call a Controller's instance method GET or POST
with the request and the groups obtained from the regex
as arguments.
"""
path_info = request.environ.get('PATH_INFO', '')
method = request.environ['REQUEST_METHOD']

for pat, app in self.dispatch_list:
mo = pat.match(path_info)
if mo != None:
args = [request]
                args.extend([i for i in mo.groups()])
if method == 'GET':
return app.GET(*args)
elif method =='POST':
return app.POST(*args)
raise NoMatchingControllerException, "No match for %s" % path_info

class WhiskyApp(object):
def __init__(self, dispatcher):
self.dispatcher = dispatcher
def __call__(self, environ, start_response):
request = Request(environ)
response = self.dispatcher.dispatch(request)
start_response(response.status(), response.headers.items())
return [response.body]

class NoddyController(object):
def GET(self, request, id):
r = Response(body="Noddy got %s" % id)
return r

class BigEarsController(object):
def __init__(self):
print "in init"
def GET(self, request, arg1, arg2):
r = Response(body="Big Ears got %s and %s" % (arg1, arg2))
return r

if __name__ == '__main__':
from paste import httpserver
dispatch_list = [
(r'/noddy/(\d+)/?$', NoddyController()),
(r'/bigears/(.*?)/(\d+)/?$', BigEarsController())
]
dispatcher = Dispatcher(dispatch_list)
app = WhiskyApp(dispatcher)
httpserver.serve(app, host='127.0.0.1', port='8080')

That’s pretty much all I need, to be honest. I’m happy using Beaker for sessions, and I’ll probably pull in cookie stuff from Paste. I bodged up an Etag cache manager for Burble, which I want to integrate. I want to write a nice base class for controllers. And that’s it. Whee!

no comments

Tags: python ~ burble ~ wsgi ~ paste ~ programming ~ web development

More things to do with Burble

Wednesday, October 03 2007

I’m committed now to using Burble for two sites. I’m about halfway through refactoring to make this possible, and I’ve discovered that my choice of framework is making this a tedious chore.

Colubrid is by the authors’ own admission based on a misapprehension about how best to use WSGI, and they recommend that you use Werkzeug now instead. Unfortunately, I didn’t realise this when I started using it.

The fundamental problem is that various important thingies are set up and torn down with each request, and various things done after instantiation, such that your init methods break. So I am forced to cut and paste where inheritance would be better, or monkeypatch.

So my very next thing to do is get off Colubrid. It would be top of the list now, but I really am desperate to get vital.org.nz off Blosxom and on to Burble. I just like my own blogging tool so much more.

no comments

Tags: burble ~ python ~ colubrid ~ wsgi

Recent comments

Rendered at 2010-08-01 22:25:24