There is no build in support for sessions because there is no right way to do it. Depending on requirements and environment you could use beaker middleware with a fitting backend or implement it yourself.
Here is an example for beaker sessions with a file-based backend.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import bottle from beaker.middleware import SessionMiddleware app = bottle.default_app() session_opts = { 'session.type': 'file', 'session.cookie_expires': 300, 'session.data_dir': './data', 'session.auto': True } app = SessionMiddleware(app, session_opts) @bottle.route('/test') def test(): s = bottle.request.environ.get('beaker.session') s['test'] = s.get('test',0) + 1 s.save() return 'Test counter: %d' % s['test'] bottle.run(app=app) |
Bottle catches all Exceptions raised in your app code, so your WSGI server won't crash. If you need exceptions to propagate to a debugging middleware, you can turn off this behaviour.
1 2 3 4 5 | import bottle app = bottle.default_app() # or bottle.app() since 0.7 app.catchall = False myapp = DebuggingMiddleware(app) bottle.run(app=myapp) |
Now, bottle only catches its own exceptions (HTTPError, HTTPResponse and BottleException) and your middleware can handle the rest.
This is not the recommend way (you should use a middleware in front of bottle to do this) but you can call other WSGI applications from within your bottle app and let bottle act as a pseudo-middleware. Here is an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from bottle import request, response, route subproject = SomeWSGIApplication() @route('/subproject/:subpath#.*#', method='ALL') def call_wsgi(subpath): new_environ = request.environ.copy() new_environ['SCRIPT_NAME'] = new_environ.get('SCRIPT_NAME','') + '/subproject' new_environ['PATH_INFO'] = '/' + subpath def start_response(status, headerlist): response.status = int(status.split()[0]) for key, value in headerlist: response.headers.append(key, value) # or .add_header() with bottle < 0.76 return app(new_environ, start_response) |
Again, this is not the recommend way to implement subprojects. It is only here because many people asked for this and to show how bottle maps to WSGI.
Bottle does not ignore trailing slashes by default.
To handle URLs like /example and /example/ the same,
you could add two @route decorators
1 2 3 | @route('/test') @route('/test/') def test(): pass |
or use regular expressions in dynamic routes
1 2 | @route('/test/?') def test(): pass |
or add a WSGI middleware to strips trailing '/' from URLs
1 2 3 4 5 6 7 8 9 10 | class StripPathMiddleware(object): def __init__(self, app): self.app = app def __call__(self, e, h): e['PATH_INFO'] = e['PATH_INFO'].rstrip('/') return self.app(e,h) app = bottle.default_app() app = StripPathMiddleware(app) bottle.run(app=app) |
Bottle searches in "./" and "./views/" for templates. In a mod_python environment, the working directory ('.') depends on your Apache settings. You should add an absolute path to the template search path
1 | bottle.TEMPLATE_PATH.insert(0,'/absolut/path/to/templates/') |
or change the working directory
1 | os.chdir(os.path.dirname(__file__)) |
so bottle searches the right paths.