2
# This file is part of Checkbox.
4
# Copyright 2008 Canonical Ltd.
6
# Checkbox is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
11
# Checkbox is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
from inspect import getargspec
21
from checkbox.lib.decorator import merge_function_metadata
24
class ArgumentReplacer(object):
25
"""A decorator helper that filters arguments to be passed to a function.
27
Create one with the original function and a function to replace
28
the arguments, and then call replace_arguments for each call to
31
def __init__(self, original_function, argument_replacer):
33
@param original_function: The function which will be called
34
soon. The function must *not* define any * or ** parameters.
35
@param argument_replacer: A function which will be called for
36
every argument. It will be passed a parameter name and the
37
associated argument. It should return the new value.
39
self.original_function = original_function
40
self.argument_replacer = argument_replacer
42
spec = getargspec(original_function)
43
self.all_arguments = spec[0]
44
if getattr(original_function, 'im_self', None) is not None:
45
# If it's bound, ignore the bound arguments.
46
self.all_arguments = self.all_arguments[1:]
48
def replace_arguments(self, args, kwargs):
49
"""Filter some arguments destined to be passed to a function.
51
@param args: Original positional arguments.
52
@param kwargs: Original keyword arguments.
54
@return: new arguments and kwarguments.
57
kwargs = kwargs.copy()
59
for name_index, name in enumerate(self.all_arguments):
60
# Ok, we've got the name of the argument. Let's find the value
61
# of the argument in our original arguments and replace it
62
# whether it's a positional or a keyword argument.
63
if name_index < len(args):
64
# Must be a positional argument
65
value = args[name_index]
66
args[name_index] = self.argument_replacer(name, value)
68
# Must be a keyword argument
69
if name not in kwargs:
70
# Oh, but it wasn't passed in. Ignore it.
73
kwargs[name] = self.argument_replacer(name, value)
77
def coerce_arguments(**schemas):
79
A decorator factory which returns a decorator which coerces arguments.
81
def replacer(name, value):
83
return schemas[name].coerce(value)
86
def decorator(original):
87
argument_replacer = ArgumentReplacer(original, replacer)
88
def replacement(*args, **kwargs):
89
new_args, new_kwargs = argument_replacer.replace_arguments(args,
91
return original(*new_args, **new_kwargs)
92
merge_function_metadata(original, replacement)