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)
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)
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
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}
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}
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 }
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
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)
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)
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)