Source code for wheezy.routing.router

""" ``router`` module.
"""

from builders import build_route
from config import route_builders as default_route_builders
from utils import route_name, merge


def url(pattern, handler, kwargs=None, name=None):
[docs] """ Converts parameters to tupple of length four. Used for convenience to name parameters and skip unused. >>> url(r'msg', 'handler', {'id': 1}, name='message') ('msg', 'handler', {'id': 1}, 'message') Usage: >>> class Login: pass >>> admin_routes = [ ... url(r'login', Login, name='signin') ... ] >>> r = PathRouter() >>> r.add_routes([ ... url(r'admin/', admin_routes, kwargs={'site_id': 1}) ... ]) """ return pattern, handler, kwargs, name class PathRouter(object):
[docs] """ """ def __init__(self, route_builders=None): """ """ self.mapping = [] self.route_map = {} self.routers = [] self.route_builders = route_builders or \ default_route_builders def add_route(self, pattern, handler,
[docs] kwargs=None, name=None): """ Adds a pattern to route table >>> r = PathRouter() >>> class Login: pass >>> r.add_route(r'login', Login) >>> assert r.route_map['login'] You can override the generated name by suppling optional ``name`` parameter >>> r.add_route(r'login', Login, name='signin') >>> assert r.route_map['signin'] >>> r.path_for('signin') 'login' """ handler_name = name or route_name(handler) route = build_route(pattern, kwargs, self.route_builders) self.route_map[handler_name] = route self.mapping.append((route, handler)) def include(self, pattern, included, kwargs=None):
[docs] """ Includes nested routes below the current. >>> r = PathRouter() >>> class Login: pass >>> admin_routes = [ ... (r'login', Login) ... ] >>> r.include(r'admin/', admin_routes) >>> route, inner = r.mapping[0] >>> inner2, route2 = r.routers[0] >>> assert route == route2 >>> assert inner == inner2 >>> assert isinstance(inner, PathRouter) """ route = build_route(pattern, kwargs, self.route_builders) inner = PathRouter(self.route_builders) inner.add_routes(included) self.mapping.append((route, inner)) self.routers.append((inner, route)) def add_routes(self, mapping):
[docs] """ Adds routes represented as a list of tuple (pattern, handler) to route table >>> r = PathRouter() >>> class Login: pass >>> r.add_routes([ ... (r'login', Login) ... ]) >>> assert r.mapping >>> assert r.route_map If ``handler`` is tuple, list or an instance of PathRouter than we proceed with ``include`` function >>> r = PathRouter() >>> class Login: pass >>> admin_routes = [(r'login', Login)] >>> r.add_routes([ ... (r'admin/', admin_routes) ... ]) >>> len(r.routers) 1 >>> len(r.mapping) 1 """ for m in mapping: l = len(m) kwargs, name = None, None if l == 2: pattern, handler = m elif l == 3: pattern, handler, kwargs = m else: pattern, handler, kwargs, name = m if isinstance(handler, (tuple, list, PathRouter)): self.include(pattern, handler, kwargs) else: self.add_route(pattern, handler, kwargs, name) def match(self, path):
[docs] """ Tries to find a match for the given path in route table. Returns a tupple of (handler, kwargs) >>> r = PathRouter() >>> class Login: pass >>> class Message: pass >>> r.add_route(r'login', Login) >>> handler, kwargs = r.match(r'login') >>> assert handler == Login >>> kwargs Tries to find inner match >>> r = PathRouter() >>> admin_routes = [ ... (r'login', Login ... )] >>> r.add_routes([ ... (r'admin/', admin_routes) ... ]) >>> handler, kwargs = r.match(r'admin/login') >>> assert handler == Login Merge kwargs >>> r = PathRouter() >>> admin_routes = [ ... (r'msg', Message, {'id': 1}) ... ] >>> r.add_routes([ ... (r'en/', admin_routes, {'lang': 'en'}) ... ]) >>> handler, kwargs = r.match(r'en/msg') >>> assert handler == Message >>> kwargs {'lang': 'en', 'id': 1} Otherwise return (None, None) >>> r = PathRouter() >>> handler, kwargs = r.match(r'') >>> handler >>> kwargs """ for route, handler in self.mapping: matched, kwargs = route.match(path) if matched >= 0: # TODO: isinstance(handler, PathRouter) handler_match = getattr(handler, 'match', None) if not handler_match: return handler, kwargs handler, kwargs_inner = handler_match( path[matched:]) if handler: if not kwargs: return handler, kwargs_inner if kwargs_inner: kwargs = kwargs.copy() merge(kwargs, kwargs_inner) return handler, kwargs return None, None def path_for(self, name, **kwargs):
[docs] """ Returns the url for the given route name. >>> r = PathRouter() >>> class Login: pass >>> r.add_route(r'login', Login) >>> r.path_for(r'login') 'login' Path for inner router >>> r = PathRouter() >>> admin_routes = [ ... (r'login', Login, None, 'signin') ... ] >>> r.add_routes([ ... (r'admin/', admin_routes) ... ]) >>> r.path_for(r'signin') 'admin/login' Otherwise None >>> r.path_for(r'unknown') """ route = self.route_map.get(name, None) if route: return route.path(kwargs) for inner, route in self.routers: inner_path = inner.path_for(name, **kwargs) if inner_path: return route.path(kwargs) + inner_path return None