Error encountered using decorator to update wrapper

attributeerror, decorator, functools, python

Solution

A decorator takes a function as an argument and returns another "decorated" function. You're passing a string and attempting to return a function which is really a function factory. `functools.wraps` and `functools.update_wrapper` expect a function. A function object would have a `__module__` attribute while instances of `str` don't have an `__module__` attribute.

Do you want to generate a function from the string "x**2"?

Your implementation of `decorator` is unnecessary. Just use `functools.wraps`:

def f(fn):
    """Converts the string fn to a function and returns it."""
    @functools.wraps(fn)
    def _f(fn):
        return eval(fn)
    return _f

However, you don't want a decorator in this case but a function factory.

def factory(exp):
    def f(**kwargs):
        return eval(exp, globals(), kwargs)
    f.__name__ = exp
    return f 

Now you can use this like this:

>>> x_squared = factory("x**2")
>>> x_squared(x=7)
49

Warning: The Surgeon General Has Determined that `eval` is Dangerous to Your Health

Problem

I've encountered a rather cryptic (to me at least) error message while trying to use a decorator to update a function's wrapper. Any ideas how I could remedy this? I've tried to make my code as general as possible so it will apply to other situations as well. ``` def decorator(d): """Make function d a decorator: d wraps a function fn.""" def _d(fn): return functools.update_wrapper(d(fn), fn) functools.update_wrapper(_d, d) return _d @decorator def f(fn): """Converts the string fn to a function and returns it. Because of the @decorator decorator, _f.__name__ should be identical to f.__name__""" f.__name__ = fn def _f(fn): return eval(fn) return _f g = f('x**2') print g.__name__ ``` Desired output: ``` >>>x**2 ``` Actual output: ``` Traceback (most recent call last): File "C:\python\swampy-2.0\testcode.py", line 18, in <module> g = f('x**2') File "C:\python\swampy-2.0\testcode.py", line 6, in _d return functools.update_wrapper(d(fn), fn) File "C:\Python27\lib\functools.py", line 33, in update_wrapper setattr(wrapper, attr, getattr(wrapped, attr)) AttributeError: 'str' object has no attribute '__module__' ```

Original source