Source code for wheezy.routing.route

""" ``route`` module.
"""

import re

from utils import merge


class Route(object):
[docs] """ Route abstract contract. """ def match(self, path):
[docs] """ if the ``path`` matches, return the end of substring matched and kwargs. Otherwise return ``(-1, None)``. >>> r = Route() >>> matched, kwargs = r.match('x') Traceback (most recent call last): ... NotImplementedError """ raise NotImplementedError() def path(self, values=None):
[docs] """ Build the path for given route. >>> r = Route() >>> r.path(dict(id=1234)) Traceback (most recent call last): ... NotImplementedError """ raise NotImplementedError() class PlainRoute(Route):
[docs] """ Route based on string equalty operation. """ def __init__(self, pattern, kwargs=None): """ Initializes the route by given ``pattern``. If pattern ends with ``/`` than it select ``startswith`` strategy. >>> r = PlainRoute(r'abc/') >>> assert r.match == r.startswith_match Otherwise ``equals`` strategy is selected. >>> r = PlainRoute(r'abc') >>> assert r.match == r.equals_match """ self.pattern = pattern self.kwargs = kwargs self.matched = len(pattern) # Choose match strategy self.match = pattern[-1:] == '/' \ and self.startswith_match \ or self.equals_match def equals_match(self, path):
[docs] """ If the ``path`` exactly equals pattern string, return end index of substring matched and a copy of ``self.kwargs``. >>> r = PlainRoute(r'abc') >>> matched, kwargs = r.equals_match('abc') >>> matched 3 >>> kwargs Match returns ``self.kwargs``. >>> r = PlainRoute(r'abc', {'a': 1}) >>> matched, kwargs = r.equals_match('abc') >>> matched 3 >>> kwargs {'a': 1} Otherwise return ``(-1, None)``. >>> matched, kwargs = r.equals_match('abc/') >>> matched -1 >>> matched, kwargs = r.equals_match('bc') >>> matched -1 >>> kwargs """ return path == self.pattern and \ (self.matched, self.kwargs) or (-1, None) def startswith_match(self, path):
[docs] """ If the ``path`` starts with pattern string, return the end of substring matched and ``self.kwargs``. >>> r = PlainRoute(r'abc') >>> matched, kwargs = r.startswith_match('abc') >>> matched 3 >>> kwargs Match returns ``self.kwargs``. >>> r = PlainRoute(r'abc', {'a': 1}) >>> matched, kwargs = r.startswith_match('abc/') >>> matched 3 >>> kwargs {'a': 1} Otherwise return ``(None, None)``. >>> matched, kwargs = r.startswith_match('bc') >>> matched -1 >>> kwargs """ return path.startswith(self.pattern) and \ (self.matched, self.kwargs) or (-1, None) def path(self, values=None):
[docs] """ Build the path for given route by simply returning the pattern used during initialization. >>> r = PlainRoute(r'abc') >>> r.path() 'abc' """ return self.pattern class RegexRoute(object):
[docs] """ Route based on regular expression matching. """ RE_SPLIT = re.compile(r'\(\?P(\<\w+\>).+?\)') def __init__(self, pattern, kwargs=None): """ """ self.pattern = pattern self.kwargs = kwargs self.regex = re.compile(pattern) def f(value): if value.startswith('<') and value.endswith('>'): value = value[1:-1] return lambda values: str(values.get(value, '')) else: return value split = RegexRoute.RE_SPLIT.split(pattern) self.parts = tuple((f(v) for v in split if v)) # Choose match strategy if kwargs: self.match = self.match_with_kwargs self.path = self.path_with_kwargs else: self.match = self.match_no_kwargs self.path = self.path_no_kwargs def match_no_kwargs(self, path):
[docs] """ If the ``path`` match the regex pattern. >>> r = RegexRoute(r'abc/(?P<id>\d+$)') >>> matched, kwargs = r.match_no_kwargs('abc/1234') >>> matched 8 >>> kwargs {'id': '1234'} Otherwise return ``(-1, None)``. >>> matched, kwargs = r.match_no_kwargs('abc/x') >>> matched -1 >>> kwargs """ m = self.regex.match(path) if m: return m.end(), m.groupdict() return -1, None def match_with_kwargs(self, path):
[docs] """ If the ``path`` match the regex pattern. >>> r = RegexRoute(r'abc/\d+', {'lang': 'en'}) >>> matched, kwargs = r.match_with_kwargs('abc/1234') >>> matched 8 >>> kwargs {'lang': 'en'} >>> r = RegexRoute(r'abc/(?P<id>\d+$)', { ... 'lang': 'en' ... }) >>> matched, kwargs = r.match_with_kwargs('abc/1234') >>> kwargs {'lang': 'en', 'id': '1234'} ``kwargs`` from ``pattern`` match must override defaults. >>> r = RegexRoute(r'abc/?(?P<id>\d*$)', {'id': '1'}) >>> matched, kwargs = r.match_with_kwargs('abc') >>> kwargs {'id': '1'} >>> matched, kwargs = r.match_with_kwargs('abc/1234') >>> kwargs {'id': '1234'} Otherwise return ``(-1, None)``. >>> matched, kwargs = r.match_with_kwargs('abc/x') >>> matched -1 >>> kwargs """ m = self.regex.match(path) if m: kwargs = m.groupdict() return (m.end(), not kwargs and self.kwargs or merge( self.kwargs.copy(), kwargs)) return -1, None def path_no_kwargs(self, values=None):
[docs] """ Build the path for the given route by substituting the named places of the regual expression. >>> r = RegexRoute( ... r'abc/(?P<month>\d+)/(?P<day>\d+)' ... ) >>> r.path_no_kwargs(dict(month = 6, day = 9)) 'abc/6/9' >>> r.path_no_kwargs(dict(month = 6)) 'abc/6' >>> r.path() 'abc' """ if values is None: values = {} parts = (isinstance(f, basestring) and f or f(values) for f in self.parts) return ''.join(parts).rstrip('/') def path_with_kwargs(self, values=None):
[docs] """ Build the path for the given route by substituting the named places of the regual expression. >>> r = RegexRoute( ... r'abc/(?P<month>\d+)/(?P<day>\d+)', ... dict(month=1, day=1) ... ) >>> r.path_with_kwargs(dict(month=6, day=9)) 'abc/6/9' >>> r.path_with_kwargs(dict(month=6)) 'abc/6/1' >>> r.path() 'abc/1/1' """ values = not values and self.kwargs or merge( self.kwargs.copy(), values) parts = (isinstance(f, basestring) and f or f(values) for f in self.parts) return ''.join(parts).rstrip('/')