undecorated

raw JSON →
0.3.0 verified Fri May 01 auth: no python maintenance

A library to undecorate Python functions, methods, or classes, returning the original callable before any decorators were applied. Version 0.3.0 is the latest; the project is in maintenance mode with no recent releases.

pip install undecorated
error AttributeError: 'function' object has no attribute '__closure__'
cause Attempting to undecorate a built-in function or a function without a closure (e.g., lambda or a function defined in C).
fix
Ensure the argument is a decorated Python function with a closure; check if the function is decorated.
error TypeError: 'int' object is not callable
cause undecorate may return a non-callable if the original object is not a function (e.g., a descriptor or property).
fix
Only use undecorate on callables that are known to be decorated functions.
error NameError: name 'undecorate' is not defined
cause Importing incorrectly (e.g., 'import undecorate' instead of 'from undecorated import undecorate').
fix
Use correct import: 'from undecorated import undecorate'
gotcha undecorate() works by inspecting closure cells, which may fail for complex decorators (e.g., functools.lru_cache, class-based decorators, or decorators that return a different type).
fix Check the result; if the original function isn't found, consider alternative approaches like storing the original manually.
gotcha Applying undecorate to an already undecorated function returns the same function; it does not error. This can mask misuses.
fix Verify the function is actually decorated before undecorating to avoid logic errors.
gotcha Does not support Python 3.12+ if decorators use new closure behavior or PEP 695 (type parameter syntax) changes. The package has not been updated for recent CPython internals.
fix Test on your Python version; if it fails, consider forking or using an alternative library.

Basic usage: undecorate a decorated function to get the original.

from undecorated import undecorate

def decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@decorator
def foo():
    return 'foo'

print(foo())            # calls wrapper
print(undecorate(foo))  # returns original function
print(undecorate(foo)()) # 'foo'