How to strip decorators from a function in Python

There's been a bit of an update for this question. If you're using Python 3, you can use __wrapped__ property for decorators from stdlib.

Here's an example from Python Cookbook, 3rd edition, section 9.3 Unwrapping decorators

>>> @somedecorator
>>> def add(x, y):
...     return x + y
...
>>> orig_add = add.__wrapped__
>>> orig_add(3, 4)
7
>>>

If you are trying to unwrap a function from custom decorator, the decorator function needs to use wraps function from functools See discussion in Python Cookbook, 3rd edition, section 9.2 Preserving function metadata when writing decorators

>>> from functools import wraps
>>> def somedecorator(func):
...    @wraps(func)
...    def wrapper(*args, **kwargs):
...       # decorator implementation here
...       # ......
...       return func(*args, **kwargs)
...
...    return wrapper

In the general case, you can't, because

@with_connection
def spam(connection):
    # Do something

is equivalent to

def spam(connection):
    # Do something

spam = with_connection(spam)

which means that the "original" spam might not even exist anymore. A (not too pretty) hack would be this:

def with_connection(f):
    def decorated(*args, **kwargs):
        f(get_connection(...), *args, **kwargs)
    decorated._original = f
    return decorated

@with_connection
def spam(connection):
    # Do something

spam._original(testcon) # calls the undecorated function

balpha's solution can be made more generalizable with this meta-decorator:

def include_original(dec):
    def meta_decorator(f):
        decorated = dec(f)
        decorated._original = f
        return decorated
    return meta_decorator

Then you can decorate your decorators with @include_original, and every one will have a testable (undecorated) version tucked away inside it.

@include_original
def shout(f):
    def _():
        string = f()
        return string.upper()
    return _



@shout
def function():
    return "hello world"

>>> print function()
HELLO_WORLD
>>> print function._original()
hello world

Behold, FuglyHackThatWillWorkForYourExampleButICantPromiseAnythingElse:

 orig_spam = spam.func_closure[0].cell_contents

Edit: For functions/methods decorated more than once and with more complicated decorators you can try using the following code. It relies on the fact, that decorated functions are __name__d differently than the original function.

def search_for_orig(decorated, orig_name):
    for obj in (c.cell_contents for c in decorated.__closure__):
        if hasattr(obj, "__name__") and obj.__name__ == orig_name:
            return obj
        if hasattr(obj, "__closure__") and obj.__closure__:
            found = search_for_orig(obj, orig_name)
            if found:
                return found
    return None

 >>> search_for_orig(spam, "spam")
 <function spam at 0x027ACD70>

It's not fool proof though. It will fail if the name of the function returned from a decorator is the same as the decorated one. The order of hasattr() checks is also a heuristic, there are decoration chains that return wrong results in any case.