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

routing.mddocs/

URL Routing

Flexible URL routing system for mapping URLs to endpoints with support for URL variables, converters, HTTP methods, and URL generation. The routing system provides both URL-to-endpoint matching and endpoint-to-URL building capabilities.

Capabilities

URL Map

The Map class manages a collection of URL rules and provides methods for binding to specific requests.

class Map:
    def __init__(self, rules=None, default_subdomain="", charset="utf-8", strict_slashes=True, merge_slashes=True, redirect_defaults=True, converters=None, sort_parameters=True, sort_key=None, host_matching=False):
        """
        Create a new URL map.
        
        Parameters:
        - rules: Initial list of Rule objects
        - default_subdomain: Default subdomain for rules
        - charset: Character encoding for URLs
        - strict_slashes: Enforce trailing slash rules
        - merge_slashes: Merge consecutive slashes in URLs
        - redirect_defaults: Redirect to canonical URLs
        - converters: Custom URL converters
        - sort_parameters: Sort URL parameters when building
        - sort_key: Custom sort key function
        - host_matching: Enable host-based routing
        """
    
    def add(self, rule_factory):
        """
        Add a rule or rule factory to the map.
        
        Parameters:
        - rule_factory: Rule object or RuleFactory
        """
    
    def bind(self, server_name, script_name="/", subdomain=None, url_scheme="http", path_info=None, method="GET", query_args=None):
        """
        Create a MapAdapter for URL matching and building.
        
        Parameters:
        - server_name: Server hostname
        - script_name: SCRIPT_NAME prefix
        - subdomain: Subdomain to match
        - url_scheme: URL scheme (http/https)
        - path_info: PATH_INFO for matching
        - method: HTTP method
        - query_args: Query arguments dict
        
        Returns:
        MapAdapter instance
        """
    
    def bind_to_environ(self, environ, server_name=None, subdomain=None):
        """
        Create MapAdapter from WSGI environ.
        
        Parameters:
        - environ: WSGI environment dictionary
        - server_name: Override server name
        - subdomain: Override subdomain
        
        Returns:
        MapAdapter instance
        """
    
    def update(self):
        """Update internal routing structures after adding rules."""

URL Rules

The Rule class defines individual URL patterns with endpoints, methods, and variable conversion.

class Rule:
    def __init__(self, string, defaults=None, subdomain=None, methods=None, build_only=False, endpoint=None, strict_slashes=None, merge_slashes=None, redirect_to=None, alias=False, host=None):
        """
        Create a new URL rule.
        
        Parameters:
        - string: URL pattern (e.g., '/user/<int:id>')
        - defaults: Default values for variables
        - subdomain: Subdomain pattern
        - methods: Allowed HTTP methods (defaults to GET)
        - build_only: Only use for URL building, not matching
        - endpoint: Endpoint name for this rule
        - strict_slashes: Override map's strict_slashes setting
        - merge_slashes: Override map's merge_slashes setting
        - redirect_to: Redirect target (string or callable)
        - alias: Whether this is an alias rule
        - host: Host pattern for host-based routing
        """
    
    def match(self, path, method="GET"):
        """
        Test if this rule matches a path.
        
        Parameters:
        - path: URL path to test
        - method: HTTP method
        
        Returns:
        Tuple of (values_dict, redirect_exception) or None
        """
    
    def build(self, values, append_unknown=True):
        """
        Build URL from endpoint values.
        
        Parameters:
        - values: Dictionary of variable values
        - append_unknown: Append unknown values as query parameters
        
        Returns:
        Tuple of (path, domain)
        """

Map Adapter

The MapAdapter class provides URL matching and building functionality for a specific request context.

class MapAdapter:
    def match(self, path_info=None, method=None, return_rule=False, query_args=None):
        """
        Match a URL to an endpoint.
        
        Parameters:
        - path_info: URL path (uses bound path if None)
        - method: HTTP method (uses bound method if None)
        - return_rule: Return matched Rule object instead of endpoint
        - query_args: Query arguments dictionary
        
        Returns:
        Tuple of (endpoint, values) or Rule object
        
        Raises:
        RequestRedirect: If redirect is required
        MethodNotAllowed: If method is not allowed
        NotFound: If no rule matches
        """
    
    def test(self, path_info=None, method="GET"):
        """
        Test if a URL matches any rule.
        
        Parameters:
        - path_info: URL path to test
        - method: HTTP method
        
        Returns:
        True if URL matches, False otherwise
        """
    
    def build(self, endpoint, values=None, method=None, force_external=False, append_unknown=True, url_scheme=None):
        """
        Build URL for an endpoint.
        
        Parameters:
        - endpoint: Endpoint name
        - values: Variable values dictionary
        - method: HTTP method hint
        - force_external: Force absolute URL
        - append_unknown: Add unknown values as query parameters
        - url_scheme: Override URL scheme
        
        Returns:
        Built URL string
        
        Raises:
        BuildError: If URL cannot be built
        """
    
    def dispatch(self, view_func, path_info=None, method=None, catch_http_exceptions=False):
        """
        Match URL and dispatch to view function.
        
        Parameters:
        - view_func: Function that takes (endpoint, values) and returns WSGI app
        - path_info: URL path
        - method: HTTP method
        - catch_http_exceptions: Catch and return HTTP exceptions as responses
        
        Returns:
        WSGI application or Response
        """

URL Converters

Built-in converters for URL variable types with validation and conversion.

class BaseConverter:
    def __init__(self, map, *args, **kwargs):
        """
        Base converter class.
        
        Parameters:
        - map: URL map instance
        - args: Converter arguments
        - kwargs: Converter keyword arguments
        """
    
    def to_python(self, value):
        """
        Convert URL value to Python object.
        
        Parameters:
        - value: URL string value
        
        Returns:
        Converted Python object
        
        Raises:
        ValidationError: If conversion fails
        """
    
    def to_url(self, value):
        """
        Convert Python object to URL string.
        
        Parameters:
        - value: Python object
        
        Returns:
        URL-safe string
        """

class UnicodeConverter(BaseConverter):
    """Default string converter, matches any text except '/'."""

class AnyConverter(BaseConverter):
    """Matches any of the specified strings."""
    def __init__(self, map, *items):
        """
        Parameters:
        - items: Valid string values
        """

class PathConverter(BaseConverter):
    """Matches strings including '/' characters."""

class IntegerConverter(BaseConverter):
    """Matches integers."""
    def __init__(self, map, fixed_digits=0, min=None, max=None):
        """
        Parameters:
        - fixed_digits: Exact number of digits required
        - min: Minimum value
        - max: Maximum value
        """

class FloatConverter(BaseConverter):
    """Matches floating point numbers."""

class UUIDConverter(BaseConverter):
    """Matches UUID strings."""

Rule Factories

Factory classes for creating multiple related rules.

class RuleFactory:
    """Base class for rule factories."""
    def get_rules(self, map):
        """
        Get list of rules from this factory.
        
        Parameters:
        - map: URL map instance
        
        Returns:
        List of Rule objects
        """

class RuleTemplate:
    def __init__(self, template):
        """
        Create rule template.
        
        Parameters:
        - template: Template Rule object
        """

class Subdomain:
    def __init__(self, subdomain, rules):
        """
        Create rules for specific subdomain.
        
        Parameters:
        - subdomain: Subdomain pattern
        - rules: List of rules or rule factories
        """

class Submount:
    def __init__(self, path, rules):
        """
        Mount rules under a path prefix.
        
        Parameters:
        - path: Path prefix
        - rules: List of rules or rule factories
        """

class EndpointPrefix:
    def __init__(self, prefix, rules):
        """
        Add prefix to rule endpoints.
        
        Parameters:
        - prefix: Endpoint prefix string
        - rules: List of rules or rule factories
        """

Routing Exceptions

Exceptions raised during URL matching and building.

class RoutingException(Exception):
    """Base exception for routing errors."""

class RequestRedirect(HTTPException, RoutingException):
    """Raised when a redirect is required."""
    code = 308
    
    def __init__(self, new_url):
        """
        Parameters:
        - new_url: Target URL for redirect
        """

class BuildError(RoutingException, LookupError):
    """Raised when URL building fails."""
    
    def __init__(self, endpoint, values, method, adapter=None):
        """
        Parameters:
        - endpoint: Endpoint that failed to build
        - values: Values dictionary used
        - method: HTTP method
        - adapter: MapAdapter instance
        """

class NoMatch(RoutingException):
    """Raised when no rule matches."""

class MethodNotAllowed(HTTPException, RoutingException):
    """Raised when HTTP method is not allowed."""
    code = 405

Usage Examples

Basic Routing Setup

from werkzeug.routing import Map, Rule
from werkzeug.wrappers import Request, Response

# Define URL rules
url_map = Map([
    Rule('/', endpoint='index'),
    Rule('/user/<username>', endpoint='user_profile'),
    Rule('/post/<int:post_id>', endpoint='show_post'),
    Rule('/api/users/<int:user_id>', endpoint='api_user', methods=['GET', 'POST']),
    Rule('/download/<path:filename>', endpoint='download_file'),
])

def view_functions(endpoint, values):
    """Route endpoints to view functions."""
    if endpoint == 'index':
        return lambda environ, start_response: Response('Home Page')(environ, start_response)
    elif endpoint == 'user_profile':
        username = values['username']
        return lambda environ, start_response: Response(f'User: {username}')(environ, start_response)
    elif endpoint == 'show_post':
        post_id = values['post_id']
        return lambda environ, start_response: Response(f'Post #{post_id}')(environ, start_response)
    # ... more endpoints

def application(environ, start_response):
    request = Request(environ)
    adapter = url_map.bind_to_environ(request.environ)
    
    try:
        endpoint, values = adapter.match()
        wsgi_app = view_functions(endpoint, values)
        return wsgi_app(environ, start_response)
    except NotFound:
        return Response('Not Found', status=404)(environ, start_response)
    except MethodNotAllowed:
        return Response('Method Not Allowed', status=405)(environ, start_response)

Custom Converters

from werkzeug.routing import BaseConverter, ValidationError
import re

class SlugConverter(BaseConverter):
    """Converter for URL-friendly slugs."""
    
    def __init__(self, map, min_length=4, max_length=50):
        super().__init__(map)
        self.min_length = min_length
        self.max_length = max_length
        self.regex = rf'[a-z0-9-]{{{min_length},{max_length}}}'
    
    def to_python(self, value):
        if not re.match(r'^[a-z0-9-]+$', value):
            raise ValidationError('Invalid slug format')
        return value
    
    def to_url(self, value):
        return str(value).lower().replace(' ', '-')

# Register custom converter
url_map = Map([
    Rule('/article/<slug:article_slug>', endpoint='article')
], converters={'slug': SlugConverter})

URL Building

from werkzeug.routing import Map, Rule

url_map = Map([
    Rule('/', endpoint='index'),
    Rule('/user/<username>', endpoint='user_profile'),
    Rule('/post/<int:post_id>/edit', endpoint='edit_post'),
])

def application(environ, start_response):
    adapter = url_map.bind_to_environ(environ)
    
    # Build URLs in templates or redirects
    home_url = adapter.build('index')  # '/'
    user_url = adapter.build('user_profile', {'username': 'john'})  # '/user/john'
    edit_url = adapter.build('edit_post', {'post_id': 123})  # '/post/123/edit'
    
    # Force external URLs
    external_url = adapter.build('user_profile', {'username': 'john'}, force_external=True)
    # 'http://example.com/user/john'
    
    response_html = f'''
    <a href="{home_url}">Home</a>
    <a href="{user_url}">User Profile</a>
    <a href="{edit_url}">Edit Post</a>
    <a href="{external_url}">External Link</a>
    '''
    
    return Response(response_html, mimetype='text/html')(environ, start_response)

Advanced Routing Patterns

from werkzeug.routing import Map, Rule, Subdomain, Submount, EndpointPrefix

# Complex routing with subdomains and submounts
url_map = Map([
    # Main site routes
    Rule('/', endpoint='index'),
    Rule('/about', endpoint='about'),
    
    # API routes with prefix
    Submount('/api/v1', [
        Rule('/users', endpoint='api.list_users'),
        Rule('/users/<int:user_id>', endpoint='api.get_user'),
        Rule('/posts', endpoint='api.list_posts'),
    ]),
    
    # Admin subdomain
    Subdomain('admin', [
        Rule('/', endpoint='admin.dashboard'),
        Rule('/users', endpoint='admin.users'),
        Rule('/settings', endpoint='admin.settings'),
    ]),
    
    # API subdomain with endpoint prefix
    Subdomain('api', [
        EndpointPrefix('api.', [
            Rule('/health', endpoint='health'),
            Rule('/status', endpoint='status'),
        ])
    ]),
])

def application(environ, start_response):
    adapter = url_map.bind_to_environ(environ)
    
    try:
        endpoint, values = adapter.match()
        
        if endpoint.startswith('api.'):
            # Handle API endpoints
            return handle_api(endpoint, values)(environ, start_response)
        elif endpoint.startswith('admin.'):
            # Handle admin endpoints  
            return handle_admin(endpoint, values)(environ, start_response)
        else:
            # Handle main site
            return handle_main(endpoint, values)(environ, start_response)
            
    except RequestRedirect as e:
        return Response('', status=e.code, headers=[('Location', e.new_url)])(environ, start_response)

Method-Based Rules

from werkzeug.routing import Map, Rule
from werkzeug.wrappers import Request, Response

url_map = Map([
    Rule('/users', endpoint='users', methods=['GET', 'POST']),
    Rule('/users/<int:user_id>', endpoint='user_detail', methods=['GET', 'PUT', 'DELETE']),
])

def handle_users(request, user_id=None):
    if user_id is None:
        # /users endpoint
        if request.method == 'GET':
            return Response('List all users')
        elif request.method == 'POST':
            return Response('Create new user')
    else:
        # /users/<id> endpoint
        if request.method == 'GET':
            return Response(f'Get user {user_id}')
        elif request.method == 'PUT':
            return Response(f'Update user {user_id}')
        elif request.method == 'DELETE':
            return Response(f'Delete user {user_id}')

def application(environ, start_response):
    request = Request(environ)
    adapter = url_map.bind_to_environ(request.environ)
    
    try:
        endpoint, values = adapter.match()
        
        if endpoint in ('users', 'user_detail'):
            response = handle_users(request, **values)
        else:
            response = Response('Not Found', status=404)
            
        return response(environ, start_response)
    except MethodNotAllowed as e:
        return Response('Method Not Allowed', status=405)(environ, start_response)

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