Python Bottle Lightweight Web Framework

Written by

in

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.py file, 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 bottle or even copying the file.
  • Built‑in development server – Run your app instantly with python myapp.py without 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 @route decorators, they map URLs to Python functions.
  • Request & Response – Accessed via bottle.request and bottle.response objects for handling headers, cookies, and data payloads.
  • Templates – Render HTML with bottle.template or integrate external engines.
  • Static Files – Serve CSS, JavaScript, or images using static_file helper.

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.

Best Practices for Maintaining Bottle Projects

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *