Applying functools.wraps to nested wrappers
<p>I have a base decorator that takes arguments but that also is built upon by other decorators. I can't seem to figure where to put the functools.wraps in order to preserve the full signature of the decorated function.</p>

<pre><code>import inspect
from functools import wraps

# Base decorator
def _process_arguments(func, *indices):
    """ Apply the pre-processing function to each selected parameter """
    @wraps(func)
    def wrap(f):
        @wraps(f)
        def wrapped_f(*args):
            params = inspect.getargspec(f)[0]

            args_out = list()
            for ind, arg in enumerate(args):
                if ind in indices:
                    args_out.append(func(arg))
                else:
                    args_out.append(arg)

            return f(*args_out)
        return wrapped_f
    return wrap


# Function that will be used to process each parameter
def double(x):
    return x * 2

# Decorator called by end user
def double_selected(*args):
    return _process_arguments(double, *args)

# End-user's function
@double_selected(2, 0)
def say_hello(a1, a2, a3):
    """ doc string for say_hello """
    print('{} {} {}'.format(a1, a2, a3))

say_hello('say', 'hello', 'arguments')
</code></pre>

<p>The result of this code should be <em>and is</em>:</p>

<pre><code>saysay hello argumentsarguments
</code></pre>

<p>However, running help on say_hello gives me:</p>

<pre><code>say_hello(*args, **kwargs)
    doc string for say_hello
</code></pre>

<p>Everything is preserved except the parameter names.</p>

<p>It seems like I just need to add another @wraps() somewhere, but where?</p>

<p>direprobs was correct in that no amount of functools wraps would get me there. bravosierra99 pointed me to somewhat related examples. However, I couldn't find a single example of signature preservation on nested decorators in which the outer decorator takes arguments.</p>

<p>The <a href="http://www.artima.com/forums/flat.jsp?forum=106&amp;thread=240845" rel="nofollow">comments on Bruce Eckel's post</a> on decorators with arguments gave me the biggest hints in achieving my desired result.</p>

<p>The key was in removing the middle function from within my _process_arguments function and placing its parameter in the next, nested function. It kind of makes sense to me now...but it works:</p>

<pre><code>import inspect
from decorator import decorator

# Base decorator
def _process_arguments(func, *indices):
    """ Apply the pre-processing function to each selected parameter """
    @decorator
    def wrapped_f(f, *args):
        params = inspect.getargspec(f)[0]

        args_out = list()
        for ind, arg in enumerate(args):
            if ind in indices:
                args_out.append(func(arg))
            else:
                args_out.append(arg)

        return f(*args_out)
    return wrapped_f


# Function that will be used to process each parameter
def double(x):
    return x * 2

# Decorator called by end user
def double_selected(*args):
    return _process_arguments(double, *args)

# End-user's function
@double_selected(2, 0)
def say_hello(a1, a2,a3):
    """ doc string for say_hello """
    print('{} {} {}'.format(a1, a2, a3))

say_hello('say', 'hello', 'arguments')
print(help(say_hello))
</code></pre>

<p>And the result:</p>

<pre><code>saysay hello argumentsarguments
Help on function say_hello in module __main__:

say_hello(a1, a2, a3)
    doc string for say_hello
</code></pre>

python python-2.7 python-decorators functools