Source

wheezy.routing / src / wheezy / routing / curly.py


""" ``curly`` module.
"""

import re

from wheezy.routing.regex import RegexRoute
from wheezy.routing.utils import outer_split


RE_SPLIT = re.compile('(?P<n>\{[\w:]+.*?\})')


def try_build_curly_route(pattern, finishing=True, kwargs=None, name=None):
    """ Convert pattern expression into regex with
        named groups and create regex route.
    """
    if isinstance(pattern, RegexRoute):
        return pattern
    if RE_SPLIT.search(pattern):
        return RegexRoute(convert(pattern), finishing, kwargs, name)
    return None


patterns = {
    # one or more digits
    'i': r'\d+',
    'int': r'\d+',
    'number': r'\d+',
    'digits': r'\d+',
    # one or more word characters
    'w': r'\w+',
    'word': r'\w+',
    # everything until ``/``
    's': r'[^/]+',
    'segment': r'[^/]+',
    'part': r'[^/]+',
    # any
    '*': r'.+',
    'a': r'.+',
    'any': r'.+',
    'rest': r'.+'
}

default_pattern = 's'


def convert(s):
    """ Convert curly expression into regex with
        named groups.
    """
    parts = outer_split(s, sep='[]')
    parts[1::2] = ['(%s)?' % p for p in map(convert, parts[1::2])]
    parts[::2] = map(convert_single, parts[::2])
    return ''.join(parts)


def convert_single(s):
    """ Convert curly expression into regex with
        named groups.
    """
    parts = RE_SPLIT.split(s)
    return ''.join(map(replace, parts))


def replace(val):
    """ Replace ``{group_name:pattern_name}`` by regex with
        named groups.
    """
    if val.startswith('{') and val.endswith('}'):
        group_name, pattern_name = parse(val[1:-1])
        pattern = patterns.get(pattern_name, pattern_name)
        return '(?P<%s>%s)' % (group_name, pattern)
    return val


def parse(s):
    """ Parse ``s`` according to ``group_name:pattern_name``.

        There is just ``group_name``, return default
        ``pattern_name``.
    """
    if ':' in s:
        return tuple(s.split(':', 1))
    return s, default_pattern