Yury Selivanov wrote:
I did provide such example earlier in this thread. I'm copying and pasting it to this mail. Please read the example carefully, as it explains why returning new types.FunctionType() is not enough.
----
Yes, your approach will work if your decorator is the only one applied. But, as I said, if you have many of them (see below), you can't just return a new function out of your decorator, you need to change the underlying "in-place". Consider the following:
def modifier(func): orig_func = func
while func.__wrapped__: func = func.__wrapped__
# patch func.__code__ and func.__closure__ return orig_func # no need to wrap anything
def some_decorator(func): def wrapper(*args, **kwargs): # some code return func(*args, **kwargs) functools.wraps(wrapper, func) return wrapper
@modifier @some_decorator def foo(): # this code needs to be verified/augmented/etc
So, in the above snippet, if you don't want to discard the @some_decorator by returning a new function object, you need to modify the 'foo' from the @modifier.
In a complex framework, where you can't guarantee that your magic decorator will always be called first, rewriting the __closure__ attribute is the only way.
So why won't this work? def f_with_new_closure(f, closure): return types.FunctionType(f.__code__, f.__globals__, f.__name__, f.__defaults__, closure) def modifier(func, closure): if func.__wrapped__: while func.__wrapped__.__wrapped__: func = func.__wrapped__ func.__wrapped__ = f_with_new_closure(func.__wrapped__, closure) else: return f_with_new_closure(func, closure) if func.__wrapped__: return f_with_new_closure(func, f_with_new_closure(func.__wrapped__)) else: return f_with_new_closure(func, closure) Cheers, Mark.