예제 #1
0
    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('/')
예제 #2
0
    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)
예제 #3
0
 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)
예제 #4
0
 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)
예제 #5
0
 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)
예제 #6
0
 def route_error(msg):
     return RouteError(f'{self.endpoint.route} is not valid: {msg}')
예제 #7
0
파일: routes.py 프로젝트: smdx023/calibre
 def route_error(msg):
     return RouteError('%s is not valid: %s' %
                       (self.endpoint.route, msg))
예제 #8
0
 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)