Looking for a fast, simple, and truly lightweight way to turn your Python ideas into web applications? Meet Bottle – a micro‑framework that packs a full‑featured web server, routing, templating, and more into a single .py file. Whether you’re building a quick prototype, a RESTful API, or a small‑scale production service, Bottle’s minimal footprint and zero‑dependency philosophy make it an attractive choice for developers who value speed, clarity, and flexibility.
What Makes Bottle a Unique Lightweight Web Framework?
Bottle is often described as a micro‑framework because it provides just enough functionality to get a web app up and running without the overhead of larger frameworks like Django or Flask. Here are the core attributes that set Bottle apart:
- Single‑file distribution – The entire framework fits into one
bottle.pyfile, which you can drop into any project or even embed directly into a script. - No external dependencies – Bottle relies only on the Python standard library, making installation as easy as
pip install bottleor even copying the file. - Built‑in development server – Run your app instantly with
python myapp.pywithout configuring a separate WSGI server. - Flexible routing – Define routes with simple decorators and support for URL parameters, regular expressions, and HTTP methods.
- Pluggable templating – Use the built‑in SimpleTemplate engine or plug in Jinja2, Mako, or any other template system you prefer.
- WSGI compliance – Deploy to any WSGI‑compatible server (Gunicorn, uWSGI, Apache mod_wsgi) for production readiness.
Getting Started with Bottle in Minutes
Installation
Because Bottle has no external dependencies, installing it is straightforward:
pip install bottle
If you prefer not to use pip, simply download the bottle.py file from the official repository and place it alongside your project files.
Creating Your First Bottle App
Below is a minimal “Hello, World!” example that demonstrates Bottle’s clean syntax:
from bottle import route, run
@route('/hello')
def hello():
return "Hello, World!"
run(host='localhost', port=8080, debug=True)
Save this as app.py and run python app.py. Open http://localhost:8080/hello in your browser to see the result.
Understanding the Core Concepts
- Routes – Defined with
@routedecorators, they map URLs to Python functions. - Request & Response – Accessed via
bottle.requestandbottle.responseobjects for handling headers, cookies, and data payloads. - Templates – Render HTML with
bottle.templateor integrate external engines. - Static Files – Serve CSS, JavaScript, or images using
static_filehelper.
Advanced Routing Techniques
Beyond simple static routes, Bottle supports dynamic URL segments, wildcard matching, and regular expressions. This flexibility is essential for building RESTful APIs and resource‑oriented services.
Dynamic URL Parameters
@route('/user/<id:int>')
def get_user(id):
return f"User ID: {id}"
Here, <id:int> extracts an integer from the URL and passes it as a function argument.
Wildcard and Regex Routes
@route('/files/<filepath:path>')
def serve_file(filepath):
return static_file(filepath, root='/var/www/files')
The <filepath:path> placeholder captures the remainder of the URL, allowing you to serve files from a directory tree.
HTTP Method Constraints
Specify allowed methods directly in the decorator to build clean, REST‑compliant endpoints:
@route('/api/item', method=['GET', 'POST'])
def item():
if request.method == 'GET':
return {"items": [...]}
else:
data = request.json
# process POST data
return {"status": "created"}, 201
Template Rendering with Bottle’s SimpleTemplate Engine
Bottle ships with a lightweight templating language called SimpleTemplate. It’s perfect for small projects where you want to avoid extra dependencies.
Basic Template Example
# template file: hello.tpl
<h1>Hello {{name}}!</h1>
from bottle import template
@route('/greet/<name>')
def greet(name):
return template('hello', name=name)
When you visit /greet/Alice, the rendered HTML will be <h1>Hello Alice!</h1>.
Using External Template Engines
If you need more advanced features, Bottle lets you plug in Jinja2 or Mako with just a few lines of code:
from bottle import Jinja2Template, route, run
@route('/jinja')
def jinja_example():
tmpl = Jinja2Template('templates/example.html')
return tmpl.render(title='Jinja2 with Bottle')
Handling Forms, JSON, and File Uploads
Modern web applications frequently interact with user input, APIs, and binary data. Bottle provides straightforward helpers for each use case.
Processing HTML Forms
@route('/login', method='POST')
def login():
username = request.forms.get('username')
password = request.forms.get('password')
# Authenticate user...
return f"Welcome, {username}!"
Working with JSON APIs
@route('/api/data', method='POST')
def api_data():
payload = request.json # Automatically parses JSON body
# Process payload...
return {"status": "success", "received": payload}
File Uploads
@route('/upload', method='POST')
def upload():
upload = request.files.get('upload')
save_path = f"/tmp/{upload.filename}"
upload.save(save_path) # Saves the file to the specified path
return f"File saved as {upload.filename}"
Deploying Bottle Applications to Production
While Bottle’s built‑in server is handy for development, production environments typically require a robust WSGI server. Below are common deployment patterns.
Using Gunicorn
# myapp.py
from bottle import default_app
application = default_app()
# In the terminal
gunicorn -w 4 -b 0.0.0.0:8000 myapp:application
Running Under uWSGI
uwsgi --http :8000 --module myapp:application --processes 4 --threads 2
Behind a Reverse Proxy (Nginx)
Configure Nginx to forward traffic to your WSGI server for added security and performance:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Testing and Debugging Bottle Apps
Effective testing ensures reliability. Bottle integrates smoothly with Python’s unittest framework and pytest. Use the TestApp class to simulate requests without a live server.
from bottle import Bottle, response
from bottle import TestApp
import unittest
app = Bottle()
@app.route('/add/<a:int>/<b:int>')
def add(a, b):
return str(a + b)
class BottleTest(unittest.TestCase):
def setUp(self):
self.test_app = TestApp(app)
def test_addition(self):
resp = self.test_app.get('/add/3/4')
self.assertEqual(resp.body.decode(), '7')
self.assertEqual(resp.status_code, 200)
if __name__ == '__main__':
unittest.main()
This approach lets you verify routes, response codes, and payloads quickly.
When to Choose Bottle Over Other Frameworks
While Flask, FastAPI, and Django dominate many Python web projects, Bottle shines in specific scenarios:
- Micro‑services or single‑function endpoints where adding a full‑stack framework would be overkill.
- Embedded systems or constrained environments that cannot afford additional dependencies.
- Educational projects that need a clear, concise example of request handling without hidden magic.
- Rapid prototyping where you want a fully functional server in a single file.
Leave a Reply