Source code for wheezy.routing.regex

"""
"""

# flake8: noqa: W605

import re

from wheezy.routing.utils import outer_split


[docs]def try_build_regex_route(pattern, finishing=True, kwargs=None, name=None): """There is no special tests to match regex selection strategy. """ if isinstance(pattern, RegexRoute): return pattern return RegexRoute(pattern, finishing, kwargs, name)
[docs]class RegexRoute(object): """Route based on regular expression matching.""" __slots__ = ( "match", "path", "path_value", "name", "path_format", "kwargs", "regex", ) exact_matches = None def __init__(self, pattern, finishing=True, kwargs=None, name=None): pattern = pattern.lstrip("^").rstrip("$") # Choose match strategy self.path_format, names = parse_pattern(pattern) if kwargs: self.kwargs = dict.fromkeys(names, "") self.kwargs.update(kwargs) if finishing: self.kwargs["route_name"] = name self.match = self.match_with_kwargs self.path = self.path_with_kwargs self.path_value = self.path_format % self.kwargs else: if finishing: self.name = name self.match = self.match_no_kwargs_finishing else: self.match = self.match_no_kwargs self.path = self.path_no_kwargs pattern = "^" + pattern if finishing: pattern = pattern + "$" self.regex = re.compile(pattern)
[docs] def match_no_kwargs(self, path): """If the ``path`` match the regex pattern.""" m = self.regex.match(path) if m: return m.end(), m.groupdict() return -1, None
[docs] def match_no_kwargs_finishing(self, path): """If the ``path`` match the regex pattern.""" m = self.regex.match(path) if m: kwargs = m.groupdict() kwargs["route_name"] = self.name return m.end(), kwargs return -1, None
[docs] def match_with_kwargs(self, path): """If the ``path`` match the regex pattern.""" m = self.regex.match(path) if m: kwargs = m.groupdict() return (m.end(), dict(self.kwargs, **kwargs)) return -1, None
[docs] def path_with_kwargs(self, values=None): """Build the path for the given route by substituting the named places of the regual expression. Specialization case: route was initialized with default kwargs. """ if values: return self.path_format % dict(self.kwargs, **values) else: return self.path_value
[docs] def path_no_kwargs(self, values): """Build the path for the given route by substituting the named places of the regual expression. Specialization case: route was initialized with no default kwargs. """ return self.path_format % values
RE_SPLIT = re.compile(r"\<(\w+)\>")
[docs]def parse_pattern(pattern): """Returns path_format and names. >>> parse_pattern(r'abc/(?P<id>[^/]+)') ('abc/%(id)s', ['id']) >>> parse_pattern(r'abc/(?P<n>[^/]+)/(?P<x>\\\w+)') ('abc/%(n)s/%(x)s', ['n', 'x']) >>> parse_pattern(r'(?P<locale>(en|ru))/home') ('%(locale)s/home', ['locale']) >>> from wheezy.routing.curly import convert >>> parse_pattern(convert(r'[{locale:(en|ru)}/]home')) ('%(locale)s/home', ['locale']) >>> parse_pattern(convert(r'item[/{id:i}]')) ('item/%(id)s', ['id']) >>> p = convert('{controller:w}[/{action:w}[/{id:i}]]') >>> parse_pattern(p) ('%(controller)s/%(action)s/%(id)s', ['controller', 'action', 'id']) """ pattern = strip_optional(pattern) parts = outer_split(pattern, sep="()") if len(parts) % 2 == 1 and not parts[-1]: parts = parts[:-1] names = [RE_SPLIT.split(p)[1] for p in parts[1::2]] parts[1::2] = ["%%(%s)s" % p for p in names] return "".join(parts), names
[docs]def strip_optional(pattern): """Strip optional regex group flag. at the beginning >>> strip_optional('((?P<locale>(en|ru))/)?home') '(?P<locale>(en|ru))/home' at the end >>> strip_optional('item(/(?P<id>\\\d+))?') 'item/(?P<id>\\\d+)' nested: >>> p = '(?P<controller>\\\w+)(/(?P<action>\\\w+)(/(?P<id>\\\d+))?)?' >>> strip_optional(p) '(?P<controller>\\\w+)/(?P<action>\\\w+)/(?P<id>\\\d+)' """ if ")?" not in pattern: return pattern parts = outer_split(pattern, sep="()") for i in range(2, len(parts), 2): part = parts[i] if part.startswith("?"): parts[i] = part[1:] parts[i - 1] = strip_optional(parts[i - 1]) else: parts[i - 1] = "(%s)" % parts[i - 1] return "".join(parts)