Beispiel #1
0
class Traject(Node):
    def __init__(self):
        super(Traject, self).__init__()
        # XXX caching is not enabled
        # also could this really be registering things in the main
        # application registry instead? if it did and we solve caching
        # for that this would get it automatically. but this would
        # require each traject base to have its own lookup
        self._inverse = Registry()

    def add_pattern(self, path, value):
        node = self
        known_variables = set()
        for segment in reversed(parse_path(path)):
            step = Step(segment)
            node = node.add(step)
            variables = set(step.names)
            if known_variables.intersection(variables):
                raise TrajectError("Duplicate variables")
            known_variables.update(variables)
        node.value = value

    def inverse(self, model_class, path, get_variables):
        # XXX should we do checking for duplicate variables here too?
        path = Path(path)
        self._inverse.register('inverse',
                               [model_class],
                               (path.interpolation_str(), get_variables))

    def __call__(self, stack):
        stack = stack[:]
        node = self
        variables = {}
        while stack:
            segment = stack.pop()
            if segment.startswith(VIEW_PREFIX):
                stack.append(segment)
                return node.value, stack, variables
            new_node, new_variables = node.get(segment)
            if new_node is None:
                stack.append(segment)
                return node.value, stack, variables
            node = new_node
            variables.update(new_variables)
        return node.value, stack, variables

    def path(self, model):
        path, get_variables = self._inverse.component('inverse', [model])
        variables = get_variables(model)
        assert isinstance(variables, dict)
        return path % variables
Beispiel #2
0
class Traject(object):
    def __init__(self):
        super(Traject, self).__init__()
        # XXX caching is not enabled
        # also could this really be registering things in the main
        # application registry instead? if it did and we solve caching
        # for that this would get it automatically.
        self._root = Node()
        self._inverse = Registry()

    def add_pattern(self, path, value, converters=None):
        node = self._root
        known_variables = set()
        for segment in reversed(parse_path(path)):
            step = Step(segment, converters)
            node = node.add(step)
            variables = set(step.names)
            if known_variables.intersection(variables):
                raise TrajectError("Duplicate variables")
            known_variables.update(variables)
        node.value = value

    def inverse(self, model_class, path, get_variables, converters,
                parameter_names):
        # XXX should we do checking for duplicate variables here too?
        path = Path(path)
        self._inverse.register('inverse',
                               [model_class],
                               (path.interpolation_str(), get_variables,
                                converters, parameter_names))

    def consume(self, stack):
        stack = stack[:]
        node = self._root
        variables = {}
        while stack:
            segment = stack.pop()
            if segment.startswith(VIEW_PREFIX):
                stack.append(segment)
                return node.value, stack, variables
            new_node, new_variables = node.get(segment)
            if new_node is None:
                stack.append(segment)
                return node.value, stack, variables
            node = new_node
            variables.update(new_variables)
        return node.value, stack, variables

    def path(self, model):
        (path, get_variables,
         converters, parameter_names) = self._inverse.component(
            'inverse', [model])
        all_variables = get_variables(model)
        assert isinstance(all_variables, dict)
        variables = {
            name: converters.get(name, IDENTITY_CONVERTER).encode(value) for
            name, value in all_variables.items()
            if name not in parameter_names}
        parameters = {
            name: converters.get(name, IDENTITY_CONVERTER).encode(value) for
            name, value in all_variables.items()
            if (name in parameter_names and
                value is not None)
            }
        return path % variables, parameters
Beispiel #3
0
class Traject(object):
    def __init__(self):
        self._step_matchers = set()
        self._conflicting_steps = set()
        self._variable_matchers = {}
        self._model_factories = {}
        self._inverse = Registry()  # XXX caching?

    def register(self, path, model_factory,
                 base_argument=False, conflicting=False):
        pattern = parse(path)
        seen_names = set()
        for p in subpatterns(pattern):
            variable_matcher = VariableMatcher(p[-1], p)
            if variable_matcher.has_variables():
                for name in variable_matcher.names:
                    if name in seen_names:
                        raise TrajectError(
                            "path '%s' has a duplicate variable: %s" %
                            (path, name)
                            )
                    seen_names.add(name)
                variable_pattern = p[:-1] + (VARIABLE,)
                variable_matchers = self._variable_matchers.setdefault(
                    variable_pattern, set())
                for m in variable_matchers:
                    if variable_matcher.conflicts(m):
                        raise TrajectError(
                            "path '%s' conflicts with path '%s'" %
                            (path, create(m.pattern)))
                variable_matchers.add(variable_matcher)
            else:
                if conflicting and p in self._step_matchers:
                    raise TrajectError(
                        "path '%s' conflicts with another" % path)
                if p in self._conflicting_steps:
                    raise TrajectError(
                        "path '%s' conflicts with another" % path)
                self._step_matchers.add(p)
                if conflicting:
                    self._conflicting_steps.add(p)

        v = self._model_factories.get(pattern)
        if v is not None:
            existing_model_factory, base_argument = v
            raise TrajectError(
                "path '%s' is already used to register model %r" %
                (path, existing_model_factory))
        self._model_factories[pattern] = model_factory, base_argument

    def register_inverse(self, model_class, path, get_variables):
        path = interpolation_path(path)
        self._inverse.register('inverse', [model_class], (path, get_variables))

    def match(self, pattern, step):
        step_pattern = self.match_step(pattern, step)
        if step_pattern is not None:
            return step_pattern, {}
        return self.match_variables(pattern, step)

    def match_step(self, pattern, step):
        pattern = pattern + (step,)
        if pattern in self._step_matchers:
            return pattern
        else:
            return None

    def match_variables(self, pattern, step):
        variable_pattern = pattern + (VARIABLE,)
        for variable_matcher in self._variable_matchers.get(variable_pattern,
                                                            []):
            matched = variable_matcher(step)
            if matched:
                break
        else:
            return None, {}
        return pattern + (variable_matcher.step,), matched

    def get_model(self, base, pattern, variables):
        v = self._model_factories.get(pattern)
        if v is None:
            return None
        model_factory, base_argument = v
        if base_argument:
            variables['base'] = base
        return model_factory(**variables)

    def get_path(self, model):
        # XXX what if path cannot be found?
        path, get_variables = self._inverse.component('inverse', [model])
        variables = get_variables(model)
        assert isinstance(variables, dict)
        return path % variables
Beispiel #4
0
class Traject(object):
    def __init__(self):
        self._step_matchers = set()
        self._conflicting_steps = set()
        self._variable_matchers = {}
        self._model_factories = {}
        self._inverse = Registry()  # XXX caching?

    def register(self,
                 path,
                 model_factory,
                 base_argument=False,
                 conflicting=False):
        pattern = parse(path)
        seen_names = set()
        for p in subpatterns(pattern):
            variable_matcher = VariableMatcher(p[-1], p)
            if variable_matcher.has_variables():
                for name in variable_matcher.names:
                    if name in seen_names:
                        raise TrajectError(
                            "path '%s' has a duplicate variable: %s" %
                            (path, name))
                    seen_names.add(name)
                variable_pattern = p[:-1] + (VARIABLE, )
                variable_matchers = self._variable_matchers.setdefault(
                    variable_pattern, set())
                for m in variable_matchers:
                    if variable_matcher.conflicts(m):
                        raise TrajectError(
                            "path '%s' conflicts with path '%s'" %
                            (path, create(m.pattern)))
                variable_matchers.add(variable_matcher)
            else:
                if conflicting and p in self._step_matchers:
                    raise TrajectError("path '%s' conflicts with another" %
                                       path)
                if p in self._conflicting_steps:
                    raise TrajectError("path '%s' conflicts with another" %
                                       path)
                self._step_matchers.add(p)
                if conflicting:
                    self._conflicting_steps.add(p)

        v = self._model_factories.get(pattern)
        if v is not None:
            existing_model_factory, base_argument = v
            raise TrajectError(
                "path '%s' is already used to register model %r" %
                (path, existing_model_factory))
        self._model_factories[pattern] = model_factory, base_argument

    def register_inverse(self, model_class, path, get_variables):
        path = interpolation_path(path)
        self._inverse.register('inverse', [model_class], (path, get_variables))

    def match(self, pattern, step):
        step_pattern = self.match_step(pattern, step)
        if step_pattern is not None:
            return step_pattern, {}
        return self.match_variables(pattern, step)

    def match_step(self, pattern, step):
        pattern = pattern + (step, )
        if pattern in self._step_matchers:
            return pattern
        else:
            return None

    def match_variables(self, pattern, step):
        variable_pattern = pattern + (VARIABLE, )
        for variable_matcher in self._variable_matchers.get(
                variable_pattern, []):
            matched = variable_matcher(step)
            if matched:
                break
        else:
            return None, {}
        return pattern + (variable_matcher.step, ), matched

    def get_model(self, base, pattern, variables):
        v = self._model_factories.get(pattern)
        if v is None:
            return None
        model_factory, base_argument = v
        if base_argument:
            variables['base'] = base
        return model_factory(**variables)

    def get_path(self, model):
        # XXX what if path cannot be found?
        path, get_variables = self._inverse.component('inverse', [model])
        variables = get_variables(model)
        assert isinstance(variables, dict)
        return path % variables