How to get the source code of a function that is wrapped by a decorator?

I wanted to print the source code for my_func, which is wrapped with my_decorator,

import inspect
from functools import wraps

def my_decorator(some_function):
    @wraps(some_function)
    def wrapper():
        some_function()

    return wrapper

@my_decorator
def my_func():
    print "supposed to return this instead!"
    return

print inspect.getsource(my_func)

However, instead, it returns the source for the shell:

@wraps(some_function)
def wrapper():
    some_function()

Is there a way to print the following:

def my_func():
    print "supposed to return this instead!"
    return

Please note that the above abstracts from a larger program. Of course, we can just get rid of the decorator in this example, but that's not what I'm looking for.

+4
source share
2 answers

In Python 2, the decoder @functools.wraps()does not set the convenience attribute __wrapped__, which adds a version of Python 3 (new in Python 3.2).

, . , :

from types import FunctionType

def extract_wrapped(decorated):
    closure = (c.cell_contents for c in decorated.__closure__)
    return next((c for c in closure if isinstance(c, FunctionType)), None)

:

print inspect.getsource(extract_wrapped(my_func))

:

>>> print inspect.getsource(extract_wrapped(my_func))
@my_decorator
def my_func():
    print "supposed to return this instead!"
    return

- functools, __wrapped__, , Python 3:

import functools

def add_wrapped(uw):
    @functools.wraps(uw)
    def update_wrapper(wrapper, wrapped, **kwargs):
        wrapper = uw(wrapper, wrapped, **kwargs)
        wrapper.__wrapped__ = wrapped
        return wrapper

functools.update_wrapper = add_wrapped(functools.update_wrapper)

, , ( functools.update_wrapper()). ( Python 2 inspect ); :

def unwrap(func):
    while hasattr(func, '__wrapped__'):
        func = func.__wrapped__
    return func

. inspect.unwrap() Python 3, .

+6

, Python 2 @functool.wraps() __wrapped__, , . , Python 3.2, bug , 3.4, v3.4 wraps().

, my_decorator(), , wraps - , , , . ( Python 2 3):

( , , functools.wraps, , functools , .)

import functools
import inspect
import sys

if sys.version_info[0:2] >= (3, 4):  # Python v3.4+?
    wraps = functools.wraps  # built-in has __wrapped__ attribute
else:
    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
              updated=functools.WRAPPER_UPDATES):
        def wrapper(f):
            f = functools.wraps(wrapped, assigned, updated)(f)
            f.__wrapped__ = wrapped  # set attribute missing in earlier versions
            return f
        return wrapper

def my_decorator(some_function):
    @wraps(some_function)
    def wrapper():
        some_function()

    return wrapper

@my_decorator
def my_func():
    print("supposed to return this instead!")
    return

print(inspect.getsource(my_func.__wrapped__))

:

@my_decorator
def my_func():
    print("supposed to return this instead!")
    return
+1

Source: https://habr.com/ru/post/1675215/


All Articles