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