def url_for(self, **kwargs): names = frozenset(kwargs) not_spec = self.required_names - names if not_spec: raise RouteError( 'The required variable(s) {} were not specified for the route: {}' .format(','.join(not_spec), self.endpoint.route)) unknown = names - self.all_names if unknown: raise RouteError( 'The variable(s) {} are not part of the route: {}'.format( ','.join(unknown), self.endpoint.route)) def quoted(x): if not isinstance(x, (str, bytes)): x = str(x) if isinstance(x, str): x = x.encode('utf-8') return urlquote(x, '') args = {k: '' for k in self.defaults} args.update(kwargs) args = {k: quoted(v) for k, v in iteritems(args)} route = self.var_pat.sub( lambda m: '{%s}' % m.group(1).partition('=')[0].lstrip('+'), self.endpoint.route) return route.format(**args).rstrip('/')
def __init__(self, endpoint_): if self.var_pat is None: Route.var_pat = self.var_pat = re.compile(r'{(.+?)}') self.endpoint = endpoint_ del endpoint_ if not self.endpoint.route.startswith('/'): raise RouteError('A route must start with /, %s does not' % self.endpoint.route) parts = filter(None, self.endpoint.route.split('/')) matchers = self.matchers = [] self.defaults = {} found_optional_part = False self.soak_up_extra = False self.type_checkers = self.endpoint.types.copy() def route_error(msg): return RouteError('%s is not valid: %s' % (self.endpoint.route, msg)) for i, p in enumerate(parts): if p[0] == '{': if p[-1] != '}': raise route_error('Invalid route, variable components must be in a {}') name = p[1:-1] is_sponge = name.startswith('+') if is_sponge: if p is not parts[-1]: raise route_error('Can only specify + in the last component') name = name[1:] if '=' in name: found_optional_part = i name, default = name.partition('=')[::2] if '{' in default or '}' in default: raise route_error('The characters {} are not allowed in default values') default = self.defaults[name] = eval(default) if isinstance(default, numbers.Number): self.type_checkers[name] = type(default) if is_sponge and not isinstance(default, type('')): raise route_error('Soak up path component must have a default value of string type') else: if found_optional_part is not False: raise route_error('Cannot have non-optional path components after optional ones') if is_sponge: self.soak_up_extra = name matchers.append((name, True)) else: if found_optional_part is not False: raise route_error('Cannot have non-optional path components after optional ones') matchers.append((None, p.__eq__)) self.names = [n for n, m in matchers if n is not None] self.all_names = frozenset(self.names) self.required_names = self.all_names - frozenset(self.defaults) argspec = inspect.getargspec(self.endpoint) if len(self.names) + 2 != len(argspec.args) - len(argspec.defaults or ()): raise route_error('Function must take %d non-default arguments' % (len(self.names) + 2)) if argspec.args[2:len(self.names)+2] != self.names: raise route_error('Function\'s argument names do not match the variable names in the route') if not frozenset(self.type_checkers).issubset(frozenset(self.names)): raise route_error('There exist type checkers that do not correspond to route variables: %r' % (set(self.type_checkers) - set(self.names))) self.min_size = found_optional_part if found_optional_part is not False else len(matchers) self.max_size = sys.maxsize if self.soak_up_extra else len(matchers)
def add(self, endpoint): if endpoint in self.endpoints: return key = endpoint.route_key if key in self.routes: raise RouteError('A route with the key: %s already exists as: %s' % (key, self.routes[key])) self.routes[key] = Route(endpoint) self.endpoints.add(endpoint)
def add(self, endpoint): if endpoint in self.endpoints: return key = endpoint.route_key if key in self.routes: raise RouteError( f'A route with the key: {key} already exists as: {self.routes[key]}' ) self.routes[key] = Route(endpoint) self.endpoints.add(endpoint)
def url_for(self, **kwargs): not_spec = self.required_names - frozenset(kwargs) if not_spec: raise RouteError( 'The required variable(s) %s were not specified for the route: %s' % (','.join(not_spec), self.endpoint.route)) args = self.defaults.copy() args.update(kwargs) route = self.var_pat.sub( lambda m: '{%s}' % m.group(1).partition('=')[0].lstrip('+'), self.endpoint.route) return route.format(**args)
def route_error(msg): return RouteError(f'{self.endpoint.route} is not valid: {msg}')
def route_error(msg): return RouteError('%s is not valid: %s' % (self.endpoint.route, msg))
def add(self, endpoint): key = route_key(endpoint.route) if key in self.routes: raise RouteError('A route with the key: %s already exists as: %s' % (key, self.routes[key])) self.routes[key] = Route(endpoint)