A month or so ago I found the Bottle Micro-framework. I'd never even heard of it, then I ran across it linked from another site and I really liked the look of it. And it really means it when it says it's a micro framework: it's a single file of around 2,200 lines.
Read the rest of this post for an example and my experimentation with user authentication.
For example, to create a WSGI web app:
from bottle import view, route, run @route('/') @route('/:name') @view('index.html') def index(name = 'world'): return locals() run()
The "@route" lines expose the URLs, this function will be used for the URLs "/" (using a default "name" argument) and "/anything", where "anything" is passed as the "name" argument. The "@view" specifies a template to be used, in this case the file "index.html" which in my example contains "Hello !" (a bottle SimpleTemplate).
My function simply returns a dictionary, in this case the local namespace.
The "run" call creates a stand-alone server, and if not given a WSGI application it will use "bottle.app" by default. Instead, you can use any WSGI infrastructure, for example I've tested it under mod_wsgi in Apache. You can also make it a CGI simply...
Unlike many very simple things, more complicated uses have been surprisingly straightforward. For example: adding debugging ("bottle.debug(True)"), handling get versus post (use "@get" or "@post" instead of "@route"), serving static files and error handlers, plugging in other templating languages... Unlike other systems, when I have started reaching for more complicated uses, bottle's learning curve has remained fairly shallow.
The down side is that bottle requires Python 2.5 or newer. Not a huge requirement, but one of my first applications I built up and then realized the machine I was deploying it on was CentOS 5.5, which has Python 2.4. Luckily it also has a "python26" package available, and I didn't need other libraries, so it worked out just fine.
Another down side is that it really has no authentication helpers. So tonight I took an example off the bottle mailing list and extended it some into something I'm calling bottlesession.
It tries to keep things simple and decorator-based by adding an "authenticator" decorator, which takes a session manager object so you can implement your own session database interface easily. You really only have to implement "save" which takes a dictionary, and "load" which returns None or a dictionary with "valid" set to True or False.
An example of using bottlelogin:
session_manager = bottlesession.PickleSession() valid_user = bottlesession.authenticator(session_manager) @route('/') @route('/:name') @valid_user() def index(name = 'world'): return '<h1>Hello %s!</h1>' % name.title() @route('/auth/login') def login(): session = session_manager.get_session() session['valid'] = True session_manager.save(session) bottle.redirect(bottle.request.COOKIES.get('validuserloginredirect', '/'))
In this case we have protected the "index" resource, and have exposed a simple "login" resource which sets the session to be valid and redirects us back to the page the user was trying to reach originally.
Obviously, you'll have to implement a session manager, but it just has to subclass the BaseSession and implement "load" and "save" methods.
I've posted a message to the bottle mailing list hoping for some discussion about it. Perhaps this is useful enough that some future version could make it's way into bottle itself.comments powered by Disqus