Blog entries tagged with 'python'

  • A simple WSGI middleware dispatcher

    By Nuno Mariz, on 8 June 2007 @ 10:41
    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.
  • Mac OS X: decoder jpeg not available

    By Nuno Mariz, on 26 January 2007 @ 12:07
    If you are using PIL(Python Imaging Library) on Mac OS X(Tiger), you will probably have a "decoder jpeg not available" when resizing a jpeg image.
    This probably means that PIL doesn't have JPEG support, because libjpeg wasn't found when PIL was being configured.
    Here is the solution:
    • Download, compile and install jpeglib and zlib
    • Edit PIL setup.py and change to:
      JPEG_ROOT = "/usr/local/include"
      ZLIB_ROOT = "/usr/local/include"
      
    • Compile:
      python setup.py build_ext -i
      
    • Test:
      python selftest.py
      
    • If the result is something like this:
      "57 tests passed."
      
    • You are ready to go:
      python setup.py install
      
  • Python 2.5 is out!

    By Nuno Mariz, on 19 September 2006 @ 14:50
    Python
    Python 2.5 is the latest major release of Python.
    As Guido it promised, wsgiref was added to the Python 2.5 Standard Library. For those who don't know what wsgi is, read this.
    You can find what's new in Python 2.5 here

Tags related