Пример #1
0
    def register_path(self, model, path,
                      variables, converters, required, get_converters,
                      absorb, code_info, model_factory):
        """Register a route.

        See :meth:`morepath.App.path` for more information.

        :param model: model class
        :param path: route
        :param variables: function that given model instance extracts
          dictionary with variables used in path and URL parameters.
        :param converters: converters structure
        :param required: required URL parameters
        :param get_converters: get a converter dynamically.
        :param absorb: absorb path
        :param code_info: the :class:`dectate.CodeInfo` object describing
          the line of code used to register the path.
        :param model_factory: function that constructs model object given
          variables extracted from path and URL parameters.
        """
        converters = converters or {}
        if get_converters is not None:
            converters.update(get_converters())
        arguments = get_arguments(model_factory, SPECIAL_ARGUMENTS)
        converters = self.converter_registry.argument_and_explicit_converters(
            arguments, converters)

        info = arginfo(model_factory)
        if info.varargs is not None:
            raise DirectiveError(
                "Cannot use varargs in function signature: %s" %
                info.varargs)
        if info.keywords is not None:
            raise DirectiveError(
                "Cannot use keywords in function signature: %s" %
                info.keywords)

        path_variables = TrajectPath(path).variables()
        for path_variable in path_variables:
            if path_variable not in arguments:
                raise DirectiveError(
                    "Variable in path not found in function signature: %s"
                    % path_variable)

        parameters = filter_arguments(arguments, path_variables)

        if required is None:
            required = set()
        required = set(required)

        extra = 'extra_parameters' in arguments

        self.add_pattern(path, model_factory, parameters,
                         converters, absorb, required, extra, code_info)

        if variables is not None:
            self.register_path_variables(model, variables)

        self.register_inverse_path(model, path, arguments, converters,
                                   absorb)
Пример #2
0
    def register_path(self, model, path, variables, converters, required,
                      get_converters, absorb, model_factory):
        """Register a route.

        See :meth:`morepath.App.path` for more information.

        :param model: model class
        :param path: route
        :param variables: function that given model instance extracts
          dictionary with variables used in path and URL parameters.
        :param converters: converters structure
        :param required: required URL parameters
        :param get_converters: get a converter dynamically.
        :param absorb: absorb path
        :param model_factory: function that constructs model object given
          variables extracted from path and URL parameters.
        """
        converters = converters or {}
        if get_converters is not None:
            converters.update(get_converters())
        arguments = get_arguments(model_factory, SPECIAL_ARGUMENTS)
        converters = self.converter_registry.argument_and_explicit_converters(
            arguments, converters)

        info = arginfo(model_factory)
        if info.varargs is not None:
            raise DirectiveError(
                "Cannot use varargs in function signature: %s" % info.varargs)
        if info.keywords is not None:
            raise DirectiveError(
                "Cannot use keywords in function signature: %s" %
                info.keywords)

        path_variables = TrajectPath(path).variables()
        for path_variable in path_variables:
            if path_variable not in arguments:
                raise DirectiveError(
                    "Variable in path not found in function signature: %s" %
                    path_variable)

        parameters = filter_arguments(arguments, path_variables)
        if required is None:
            required = set()
        required = set(required)

        extra = 'extra_parameters' in arguments
        if parameters or converters or required or extra:
            parameter_factory = ParameterFactory(parameters, converters,
                                                 required, extra)
        else:
            parameter_factory = _simple_parameter_factory

        self.add_pattern(path, (model_factory, parameter_factory), converters,
                         absorb)

        if variables is not None:
            self.register_path_variables(model, variables)

        self.register_inverse_path(model, path, arguments, converters, absorb)
Пример #3
0
    def add_pattern(
        self,
        path,
        model_factory,
        defaults=None,
        converters=None,
        absorb=False,
        required=None,
        extra=None,
        code_info=None,
    ):
        """Add a route to the tree.

        :param path: route to add.
        :param model_factory: the factory used to construct the model instance
        :param defaults: mapping of URL parameters to default value
          for parameter
        :param converters: converters to store with the end step of the route
        :param absorb: does this path absorb all segments
        :param required: list or set of required URL parameters
        :param extra: bool indicating whether extra parameters are expected
        :param code_info: :class:`dectate.CodeInfo` instance describing
          the code line that registered this path.

        """
        node = self._root
        known_variables = set()
        for segment in 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)
        if defaults or converters or required or extra:
            parameter_factory = ParameterFactory(defaults, converters,
                                                 required, extra)
        else:
            parameter_factory = _simple_parameter_factory

        model_args = set(arginfo(model_factory).args)
        wants_request = "request" in model_args
        wants_app = "app" in model_args

        def create(path_variables, request):
            variables = parameter_factory(request)
            if wants_request:
                variables["request"] = request
            if wants_app:
                variables["app"] = request.app
            request.path_code_info = code_info
            variables.update(path_variables)
            return model_factory(**variables)

        node.create = create
        node.absorb = absorb
Пример #4
0
def get_arguments(callable, exclude):
    """Get dictionary with arguments and their default value.

    If no default is given, default value is taken to be None.
    """
    info = arginfo(callable)
    defaults = info.defaults or []
    defaults = [None] * (len(info.args) - len(defaults)) + list(defaults)
    return {name: default for (name, default) in zip(info.args, defaults)
            if name not in exclude}
Пример #5
0
def get_arguments(callable, exclude):
    """Introspect callable to get callable arguments and their defaults.

    :param callable: callable object such as a function.
    :param exclude: a set of names not to extract.
    :return: a dict with as keys the argument names and as values the
       default values (or ``None`` if no default value was defined).
    """
    info = arginfo(callable)
    defaults = info.defaults or []
    defaults = [None] * (len(info.args) - len(defaults)) + list(defaults)
    return {name: default for (name, default) in zip(info.args, defaults)
            if name not in exclude}
Пример #6
0
def get_arguments(callable, exclude):
    """Introspect callable to get callable arguments and their defaults.

    :param callable: callable object such as a function.
    :param exclude: a set of names not to extract.
    :return: a dict with as keys the argument names and as values the
       default values (or ``None`` if no default value was defined).
    """
    info = arginfo(callable)
    defaults = info.defaults or []
    defaults = [None] * (len(info.args) - len(defaults)) + list(defaults)
    return {
        name: default
        for (name, default) in zip(info.args, defaults) if name not in exclude
    }
Пример #7
0
    def add_pattern(self, path, model_factory, defaults=None,
                    converters=None, absorb=False, required=None,
                    extra=None, code_info=None):
        """Add a route to the tree.

        :param path: route to add.
        :param model_factory: the factory used to construct the model instance
        :param defaults: mapping of URL parameters to default value
          for parameter
        :param converters: converters to store with the end step of the route
        :param absorb: does this path absorb all segments
        :param required: list or set of required URL parameters
        :param extra: bool indicating whether extra parameters are expected
        :param code_info: :class:`dectate.CodeInfo` instance describing
          the code line that registered this path.

        """
        node = self._root
        known_variables = set()
        for segment in 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)
        if defaults or converters or required or extra:
            parameter_factory = ParameterFactory(
                defaults, converters, required, extra)
        else:
            parameter_factory = _simple_parameter_factory

        model_args = set(arginfo(model_factory).args)
        wants_request = 'request' in model_args
        wants_app = 'app' in model_args

        def create(path_variables, request):
            variables = parameter_factory(request)
            if wants_request:
                variables['request'] = request
            if wants_app:
                variables['app'] = request.app
            request.path_code_info = code_info
            variables.update(path_variables)
            return model_factory(**variables)

        node.create = create
        node.absorb = absorb
Пример #8
0
def mapply(func, *args, **kw):
    """Apply keyword arguments to function only if it defines them.

    So this works without error as ``b`` is ignored::

      def foo(a):
          pass

      mapply(foo, a=1, b=2)

    Zope has an mapply that does this but a lot more too. py.test has
    an implementation of getting the argument names for a
    function/method that we've borrowed.
    """
    info = arginfo(func)
    if info.varkw:
        return func(*args, **kw)
    # XXX we don't support nested arguments
    new_kw = dict((name, kw[name]) for name in info.args if name in kw)
    return func(*args, **new_kw)
Пример #9
0
def register_path(app, model, path, variables, converters, required,
                  get_converters, absorb, model_factory):
    traject = app.traject

    converters = converters or {}
    if get_converters is not None:
        converters.update(get_converters())
    arguments = get_arguments(model_factory, SPECIAL_ARGUMENTS)
    converters = app.argument_and_explicit_converters(arguments, converters)
    path_variables = Path(path).variables()

    info = arginfo(model_factory)
    if info.varargs is not None:
        raise DirectiveError(
            "Cannot use varargs in function signature: %s" % info.varargs)
    if info.keywords is not None:
        raise DirectiveError(
            "Cannot use keywords in function signature: %s" % info.keywords)
    for path_variable in path_variables:
        if path_variable not in arguments:
            raise DirectiveError(
                "Variable in path not found in function signature: %s"
                % path_variable)

    parameters = get_url_parameters(arguments, path_variables)
    if required is None:
        required = set()
    required = set(required)
    parameter_factory = ParameterFactory(parameters, converters, required,
                                         'extra_parameters' in arguments)
    if variables is None:
        variables = get_variables_func(arguments, {})

    traject.add_pattern(path, (model_factory, parameter_factory),
                        converters, absorb)

    inverse = Inverse(path, variables, converters, parameters.keys(),
                      absorb)
    app.register_function(generic.path, inverse, obj=model)
Пример #10
0
    def register_path(self, model, path,
                      variables, converters, required, get_converters,
                      absorb, model_factory):
        """Register a route.

        See :meth:`morepath.App.path` for more information.

        :param model: model class
        :param path: route
        :param variables: function that given model instance extracts
          dictionary with variables used in path and URL parameters.
        :param converters: converters structure
        :param required: required URL parameters
        :param get_converters: get a converter dynamically.
        :param absorb: absorb path
        :param model_factory: function that constructs model object given
          variables extracted from path and URL parameters.
        """
        converters = converters or {}
        if get_converters is not None:
            converters.update(get_converters())
        arguments = get_arguments(model_factory, SPECIAL_ARGUMENTS)
        converters = self.converter_registry.argument_and_explicit_converters(
            arguments, converters)
        path_variables = Path(path).variables()

        info = arginfo(model_factory)
        if info.varargs is not None:
            raise DirectiveError(
                "Cannot use varargs in function signature: %s" %
                info.varargs)
        if info.keywords is not None:
            raise DirectiveError(
                "Cannot use keywords in function signature: %s" %
                info.keywords)
        for path_variable in path_variables:
            if path_variable not in arguments:
                raise DirectiveError(
                    "Variable in path not found in function signature: %s"
                    % path_variable)

        parameters = filter_arguments(arguments, path_variables)
        if required is None:
            required = set()
        required = set(required)
        parameter_factory = ParameterFactory(parameters, converters, required,
                                             'extra_parameters' in arguments)
        if variables is None:
            variables = get_variables_func(arguments, {})

        self.add_pattern(path, (model_factory, parameter_factory),
                         converters, absorb)

        inverse = Inverse(path, variables, converters, parameters.keys(),
                          absorb)
        self.reg_registry.register_function(generic.path, inverse, obj=model)

        def class_path(cls, variables):
            return inverse.with_variables(variables)
        self.reg_registry.register_function(
            generic.class_path, class_path, cls=model)