CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-werkzeug

The comprehensive WSGI web application library providing essential utilities and components for building Python web applications.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

middleware.mddocs/

Middleware

Collection of WSGI middleware components for common functionality including static file serving, proxy handling, profiling, and application dispatching. These middleware classes provide reusable functionality that can be wrapped around WSGI applications.

Capabilities

Shared Data Middleware

Serves static files during development or for simple deployments without requiring a separate web server.

class SharedDataMiddleware:
    def __init__(self, app, exports, disallow=None, cache=True, cache_timeout=43200, fallback_mimetype="text/plain"):
        """
        WSGI middleware for serving static files.
        
        Parameters:
        - app: WSGI application to wrap
        - exports: Dict mapping URL paths to filesystem paths or package data
        - disallow: List of fnmatch patterns for files to deny access to
        - cache: Whether to send caching headers
        - cache_timeout: Cache timeout in seconds (default: 12 hours)
        - fallback_mimetype: Default MIME type for unknown files
        """
    
    def is_allowed(self, filename):
        """
        Check if a filename is allowed to be served.
        
        Parameters:
        - filename: Filename to check against disallow patterns
        
        Returns:
        True if file is allowed, False if blocked by disallow patterns
        """
    
    def __call__(self, environ, start_response):
        """
        WSGI application callable.
        
        Serves static files if path matches exports, otherwise forwards
        to the wrapped application.
        """

Proxy Fix Middleware

Handles X-Forwarded headers when the application is behind a proxy server.

class ProxyFix:
    def __init__(self, app, x_for=1, x_proto=1, x_host=0, x_port=0, x_prefix=0):
        """
        Adjust WSGI environ based on X-Forwarded headers from proxies.
        
        Parameters:
        - app: WSGI application to wrap
        - x_for: Number of X-Forwarded-For values to trust (sets REMOTE_ADDR)
        - x_proto: Number of X-Forwarded-Proto values to trust (sets wsgi.url_scheme)
        - x_host: Number of X-Forwarded-Host values to trust (sets HTTP_HOST, SERVER_NAME, SERVER_PORT)
        - x_port: Number of X-Forwarded-Port values to trust (sets HTTP_HOST, SERVER_PORT)
        - x_prefix: Number of X-Forwarded-Prefix values to trust (sets SCRIPT_NAME)
        
        Note: Only trust headers from the number of proxies you expect.
        Trusting wrong values is a security vulnerability.
        """
    
    def __call__(self, environ, start_response):
        """
        WSGI application callable.
        
        Processes X-Forwarded headers and updates environ accordingly.
        Original values are preserved in environ['werkzeug.proxy_fix.orig'].
        """

Dispatcher Middleware

Combines multiple WSGI applications into a single application based on URL paths.

class DispatcherMiddleware:
    def __init__(self, app, mounts=None):
        """
        Dispatch requests to different applications based on path prefixes.
        
        Parameters:
        - app: Default WSGI application for unmatched paths
        - mounts: Dict mapping path prefixes to WSGI applications
        """
    
    def __call__(self, environ, start_response):
        """
        WSGI application callable.
        
        Dispatches request to appropriate mounted application or default app.
        Updates SCRIPT_NAME and PATH_INFO appropriately for mounted apps.
        """

Profiler Middleware

Profiles each request using Python's cProfile module to identify performance bottlenecks.

class ProfilerMiddleware:
    def __init__(self, app, stream=sys.stdout, sort_by=("time", "calls"), restrictions=(), profile_dir=None, filename_format="{method}.{path}.{elapsed:.0f}ms.{time:.0f}.prof"):
        """
        Profile WSGI application performance.
        
        Parameters:
        - app: WSGI application to wrap
        - stream: Stream to write profiling stats to (None to disable)
        - sort_by: Tuple of columns to sort stats by
        - restrictions: Tuple of restrictions to filter stats
        - profile_dir: Directory to save profile data files
        - filename_format: Format string for profile filenames or callable
        """
    
    def __call__(self, environ, start_response):
        """
        WSGI application callable.
        
        Profiles the wrapped application and outputs stats according to configuration.
        """

Lint Middleware

Validates WSGI compliance of applications and middleware for debugging.

class LintMiddleware:
    def __init__(self, app):
        """
        WSGI compliance checking middleware.
        
        Parameters:
        - app: WSGI application to validate
        
        Note: This middleware checks for WSGI spec compliance and will
        raise warnings or errors for violations. Use during development only.
        """
    
    def __call__(self, environ, start_response):
        """
        WSGI application callable.
        
        Validates environ dict, start_response callback, and application
        return value for WSGI spec compliance.
        """

HTTP Proxy Middleware

Provides HTTP proxy functionality for forwarding requests to remote servers.

class ProxyMiddleware:
    def __init__(self, app, targets, chunk_size=2 << 13, timeout=10):
        """
        HTTP proxy middleware for forwarding requests.
        
        Parameters:
        - app: WSGI application to wrap (fallback for non-proxied requests)
        - targets: Dict mapping path prefixes to target URLs
        - chunk_size: Size of chunks when streaming responses
        - timeout: Timeout for proxy requests
        """
    
    def __call__(self, environ, start_response):
        """
        WSGI application callable.
        
        Forwards requests matching target paths to remote servers,
        otherwise passes to wrapped application.
        """

Usage Examples

Static File Serving

from werkzeug.middleware.shared_data import SharedDataMiddleware
from werkzeug.wrappers import Request, Response
import os

def app(environ, start_response):
    request = Request(environ)
    response = Response(f'API endpoint: {request.path}')
    return response(environ, start_response)

# Serve static files from multiple locations
wrapped_app = SharedDataMiddleware(app, {
    '/static': os.path.join(os.path.dirname(__file__), 'static'),
    '/uploads': '/var/www/uploads',
    '/assets': ('mypackage', 'assets'),  # Package data
})

# With custom configuration
wrapped_app = SharedDataMiddleware(
    app,
    {'/static': './static'},
    disallow=['*.secret', '*.key', '.htaccess'],  # Block sensitive files
    cache=True,
    cache_timeout=3600,  # 1 hour cache
    fallback_mimetype='application/octet-stream'
)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 8000, wrapped_app, use_reloader=True)

Proxy Configuration

from werkzeug.middleware.proxy_fix import ProxyFix

def app(environ, start_response):
    # Access real client information after proxy processing
    remote_addr = environ.get('REMOTE_ADDR')
    scheme = environ.get('wsgi.url_scheme')
    host = environ.get('HTTP_HOST')
    
    response = Response(f'Client: {remote_addr}, Scheme: {scheme}, Host: {host}')
    return response(environ, start_response)

# Configure for deployment behind nginx
# nginx sets X-Forwarded-For and X-Forwarded-Proto
proxy_app = ProxyFix(app, x_for=1, x_proto=1)

# Configure for deployment behind multiple proxies
# Load balancer -> nginx -> app
multi_proxy_app = ProxyFix(app, x_for=2, x_proto=1, x_host=1)

# Check original values if needed
def debug_app(environ, start_response):
    orig = environ.get('werkzeug.proxy_fix.orig', {})
    current_addr = environ.get('REMOTE_ADDR')
    original_addr = orig.get('REMOTE_ADDR')
    
    response = Response(f'Current: {current_addr}, Original: {original_addr}')
    return response(environ, start_response)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 8000, proxy_app)

Application Dispatching

from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.wrappers import Request, Response

# API application
def api_app(environ, start_response):
    request = Request(environ)
    
    if request.path == '/users':
        response = Response('{"users": []}', mimetype='application/json')
    else:
        response = Response('{"error": "Not found"}', status=404)
    
    return response(environ, start_response)

# Admin application
def admin_app(environ, start_response):
    request = Request(environ)
    response = Response(f'<h1>Admin Panel</h1><p>Path: {request.path}</p>', 
                       mimetype='text/html')
    return response(environ, start_response)

# Frontend application (catch-all)
def frontend_app(environ, start_response):
    request = Request(environ)
    
    # Serve SPA for all frontend routes
    if request.path.startswith('/app/'):
        html = '''
        <html>
        <head><title>My App</title></head>
        <body>
            <div id="app">Single Page Application</div>
            <script>console.log("Route: " + location.pathname)</script>
        </body>
        </html>
        '''
        response = Response(html, mimetype='text/html')
    else:
        response = Response('Welcome! Try /app/, /api/, or /admin/')
    
    return response(environ, start_response)

# Combine applications
combined_app = DispatcherMiddleware(frontend_app, {
    '/api': api_app,
    '/admin': admin_app,
})

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 8000, combined_app, use_reloader=True)

Performance Profiling

from werkzeug.middleware.profiler import ProfilerMiddleware
from werkzeug.wrappers import Request, Response
import time
import random

def slow_app(environ, start_response):
    request = Request(environ)
    
    # Simulate different performance characteristics
    if request.path == '/slow':
        time.sleep(0.5)  # Simulate slow operation
        
    elif request.path == '/compute':
        # CPU intensive operation
        result = sum(i**2 for i in range(10000))
        
    elif request.path == '/random':
        # Variable performance
        time.sleep(random.uniform(0.1, 0.3))
    
    response = Response(f'Processed {request.path}')
    return response(environ, start_response)

# Profile to stdout with custom sorting
profiled_app = ProfilerMiddleware(
    slow_app,
    sort_by=('cumulative', 'calls'),
    restrictions=(30,)  # Show top 30 functions
)

# Save profile data to files
import os
profile_dir = './profiles'
os.makedirs(profile_dir, exist_ok=True)

file_profiled_app = ProfilerMiddleware(
    slow_app,
    stream=None,  # Don't print to stdout
    profile_dir=profile_dir,
    filename_format='{method}-{path}-{elapsed:.0f}ms.prof'
)

# Custom filename generator
def custom_filename(environ):
    profiler_info = environ['werkzeug.profiler']
    path = environ.get('PATH_INFO', 'root').replace('/', '-')
    elapsed = profiler_info['elapsed']
    return f'profile-{path}-{elapsed:.1f}ms.prof'

custom_profiled_app = ProfilerMiddleware(
    slow_app,
    profile_dir=profile_dir,
    filename_format=custom_filename
)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    print("Visit /slow, /compute, or /random to see profiling output")
    run_simple('localhost', 8000, profiled_app, use_reloader=True)

WSGI Compliance Testing

from werkzeug.middleware.lint import LintMiddleware
from werkzeug.wrappers import Response

# Application with potential WSGI violations
def problematic_app(environ, start_response):
    # This app has some WSGI compliance issues
    
    # Issue 1: Not checking if start_response was called
    response = Response('Hello')
    
    # Issue 2: Returning string instead of bytes iterable
    # return 'This would cause a lint error'  # Wrong!
    
    # Correct WSGI return
    return response(environ, start_response)

# Wrap with lint middleware for development
linted_app = LintMiddleware(problematic_app)

# This will catch and warn about WSGI spec violations
if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 8000, linted_app, use_reloader=True)

HTTP Proxy

from werkzeug.middleware.http_proxy import ProxyMiddleware

def local_app(environ, start_response):
    request = Request(environ)
    response = Response(f'Local app handling: {request.path}')
    return response(environ, start_response)

# Proxy certain paths to remote services
proxied_app = ProxyMiddleware(local_app, {
    '/api/external': 'https://api.example.com',
    '/cdn': 'https://cdn.example.com',
})

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    # Requests to /api/external/* will be forwarded to api.example.com
    # Other requests handled by local_app
    run_simple('localhost', 8000, proxied_app)

Combining Multiple Middleware

from werkzeug.middleware.shared_data import SharedDataMiddleware
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.middleware.profiler import ProfilerMiddleware
from werkzeug.middleware.dispatcher import DispatcherMiddleware

def api_app(environ, start_response):
    response = Response('{"api": "v1"}', mimetype='application/json')
    return response(environ, start_response)

def web_app(environ, start_response):
    response = Response('<h1>Web Application</h1>', mimetype='text/html')
    return response(environ, start_response)

# Layer middleware (applied inside-out)
app = DispatcherMiddleware(web_app, {'/api': api_app})

# Add static file serving
app = SharedDataMiddleware(app, {
    '/static': './static',
    '/favicon.ico': './static/favicon.ico'
})

# Add proxy fix for production deployment
app = ProxyFix(app, x_for=1, x_proto=1)

# Add profiling for development
if __name__ == '__main__':
    # Only add profiler in development
    app = ProfilerMiddleware(app, sort_by=('cumulative',))
    
    from werkzeug.serving import run_simple
    run_simple('localhost', 8000, app, use_reloader=True)

Development vs Production Configuration

import os
from werkzeug.middleware.shared_data import SharedDataMiddleware
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.middleware.profiler import ProfilerMiddleware

def create_app():
    def app(environ, start_response):
        response = Response('Hello World!')
        return response(environ, start_response)
    
    return app

def wrap_app_for_environment(app):
    environment = os.getenv('ENVIRONMENT', 'development')
    
    if environment == 'development':
        # Development middleware
        app = SharedDataMiddleware(app, {'/static': './static'})
        app = ProfilerMiddleware(app)
        
    elif environment == 'production':
        # Production middleware  
        app = ProxyFix(app, x_for=1, x_proto=1, x_host=1)
        # Note: Use proper web server for static files in production
        
    return app

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    
    app = create_app()
    app = wrap_app_for_environment(app)
    
    run_simple('localhost', 8000, app, use_reloader=True)

Custom Middleware Example

from werkzeug.wrappers import Request, Response

class RequestTimingMiddleware:
    """Custom middleware to add request timing headers."""
    
    def __init__(self, app):
        self.app = app
    
    def __call__(self, environ, start_response):
        import time
        
        start_time = time.time()
        
        def timing_start_response(status, headers, exc_info=None):
            # Add timing header
            elapsed = time.time() - start_time
            headers.append(('X-Response-Time', f'{elapsed:.3f}s'))
            return start_response(status, headers, exc_info)
        
        return self.app(environ, timing_start_response)

def app(environ, start_response):
    import time
    time.sleep(0.1)  # Simulate processing
    response = Response('Timed response')
    return response(environ, start_response)

# Apply custom middleware
timed_app = RequestTimingMiddleware(app)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 8000, timed_app)

Install with Tessl CLI

npx tessl i tessl/pypi-werkzeug

docs

data-structures.md

dev-server.md

exceptions.md

http-utilities.md

index.md

middleware.md

request-response.md

routing.md

security.md

testing.md

url-wsgi-utils.md

tile.json