-
Django has a code error notifications mechanism when a view raises an exception. It will email the people in ADMIN tuple(settings documentation) in settings.py with the full exception information and displays the default 500.html template.
This only happens when DEBUG=False in the settings.py.It's possible to set a handle that change this behavior with a handler500 variable in the root urls.py.
So, we can easily write a simple view that sends an error notification to our jabber account.First of all, you need to install xmpppy and dnspython:
$ easy_install xmpppy $ easy_install dnspython
Add to settings.py the jabber parameters such as the jabber id, password, recipient, etc.:
JABBER_ERROR_NOTIFICATION = True JABBER_ID = 'your_jabberid@jabberdomain.com' JABBER_PASSWORD = 'your_jabber_password' JABBER_RECIPIENT = 'recipient@jabberdomain.com' JABBER_ERROR_TEXT = 'An error occurred in "Project Name", please check your email.'
Start a new app named errors or something else and add it to the INSTALLED_APPS tuple in the settings.py:
python manage.py startapp errors
Add a handler500 variable with the view in the root urls.py:
handler500 = 'errors.views.server_error_jabber'
Finally add the view in errors.views that sends a jabber notification and returns a 500 error page:
from django.views.defaults import server_error from django.conf import settings import xmpp, time def server_error_jabber(request, template_name='500.html'): if settings.JABBER_ERROR_NOTIFICATION: jid = xmpp.protocol.JID(settings.JABBER_ID) cl = xmpp.Client(jid.getDomain(), debug=[]) conn = cl.connect() if conn: auth = cl.auth(jid.getNode(), settings.JABBER_PASSWORD, resource=jid.getResource()) if auth: id = cl.send(xmpp.protocol.Message(settings.JABBER_RECIPIENT, settings.JABBER_ERROR_TEXT)) # Some older servers will not send the message if you disconnect immediately after sending time.sleep(1) return server_error(request, template_name)NOTE: Don't forget to set DEBUG=False in the settings.py. -

A simple templatetag for adding to the template context a variable with the user timeline from Twitter.
It uses the CachedContextUpdatingNode snippet for caching from Jacob Kaplan-Moss.
The reason that is necessary to cache content is because Twitter limits the number of accesses to the API.
This only works if the cache is enabled on your settings.py.class TwitterNode(CachedContextUpdatingNode): cache_timeout = 1800 # 30 Minutes, maybe you want to change this def __init__(self, username, varname): self.username = username self.varname = varname def make_datetime(self, created_at): return datetime.fromtimestamp(mktime(strptime(created_at, '%a %b %d %H:%M:%S +0000 %Y'))) def get_cache_key(self, context): return 'twitter_user_timeline_cache' def get_content(self, context): try: response = urllib.urlopen('http://twitter.com/statuses/user_timeline/%s.json' % self.username).read() json = simplejson.loads(response) except: return {self.varname : None} for i in range(len(json)): json[i]['created_at'] = self.make_datetime(json[i]['created_at']) return {self.varname : json} @register.tag def twitter_user_timeline(parser, token): bits = token.contents.split() if len(bits) != 4: raise TemplateSyntaxError, "twitter_user_timeline tag takes exactly three arguments" if bits[2] != 'as': raise TemplateSyntaxError, "second argument to twitter_user_timeline tag must be 'as'" return TwitterNode(bits[1], bits[3])Usage:{% twitter_user_timeline username as twitter_entries %} {% if twitter_entries %} {% for entry in twitter_entries %} {{ entry.created_at|date:"d M Y H:i" }} - {{ entry.text }} {% endfor %} {% endif %}Use the source, Luke. -
The Web Server Gateway Interface (WSGI) is a standard interface between web server software and web applications written in Python. Having a standard interface makes it easy to use an application that supports WSGI with a number of different web servers.
One implementation is wsgiref that was added to Python 2.5 Standard Library.
Here is a simple web application that writes "Hello World":def index(environ, start_response): start_response("200 Ok", [('content-type', 'text/html')]) return ['Hello World!'] if __name__ == "__main__": from wsgiref.simple_server import make_server server = make_server(HOST, PORT, index) print 'Starting up HTTP server on port %i...' % PORT server.serve_forever()
This is nice, but is not very useful for us, so lets add some kind of controller(or url dispatcher):from dispatcher import Dispatcher dispatcher = Dispatcher() dispatcher.add(r'^/$', 'views.index') dispatcher.add(r'^/hello/(?P<username>\w+)/$', 'views.hello') HOST = 'localhost' PORT = 8000 if __name__ == "__main__": from wsgiref.simple_server import make_server server = make_server(HOST, PORT, dispatcher) print 'Starting up HTTP server on port %i...' % PORT server.serve_forever()
As you can see I've used a regular expression for the url mapping, just like Django uses.
Here is the dispatcher(dispatcher.py):import re class Dispatcher(object): def __init__(self, handle404 = None): self.urls = dict() self.request_path = '' if handle404: self.handle404 = handle404 else: self.handle404 = self._404 def __call__(self, environ, start_response): self.request_path = environ.get('PATH_INFO', '') for url in self.urls: regex = re.compile(url) if regex.match(self.request_path): m = regex.match(self.request_path) mod_name, func_name = self._get_mod_func(self.urls[url]) try: callback = getattr(__import__(mod_name, {}, {}, ['']), func_name) except ImportError, e: raise Exception, "Could not import %s. Error was: %s" % (mod_name, str(e)) except AttributeError, e: raise Exception, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) args = (environ, start_response) kwargs = dict() for i in regex.groupindex: kwargs[i] = m.group(i) # Run callback with environ, start_response and args return callback(*args, **kwargs) # No match with the defined urls return self.handle404(environ, start_response) def _get_mod_func(self, callback): """ Converts 'path.to.module.funtion' to ['path.to.module', 'function'] """ try: d = callback.rindex('.') except ValueError: return callback, '' return callback[:d], callback[d+1:] def _404(self, environ, start_response): start_response("404 Not Found", [('content-type', 'text/html')]) return ['Not Found'] def add(self, regex, handler): self.urls[regex] = handler
And here is the views(views.py):def index(environ, start_response): start_response("200 Ok", [('content-type', 'text/html')]) return ['Index'] def hello(environ, start_response, username): start_response("200 Ok", [('content-type', 'text/html')]) return ['Hello %s' % username]
Simple eh?
This is just a start, now we can add more features, like encapsulate the start_response method and add some kind of HttpResponse.
I don't what do reinvent the wheel here and add another web framework to Python, just like Joe Gregorio says in this article. But to prove how trivial is to make a simple framework with WSGI and don't worry about the deployment at development phase.

My name is Nuno Mariz and this is my weblog. I'm a software engineer, living in Porto, Portugal. My interests are: 


