Python
Get Func Source

Get Function Source

Requirements

  • astunparse

optional (for test):

  • astpretty
  • lk-logger

Code

get_func_source.py:

import ast
import inspect
import typing as t
from types import FunctionType
 
from astunparse import unparse
 
 
def get_source(
        func: FunctionType,
        strip_decorators: bool = True,
        strip_signature: bool = False,  # aka. body_only
        strip_return: bool = False,
) -> str:
    """
    https://stackoverflow.com/a/57040815
    notice: if either `strip_decorators` or `strip_signature` is True, the
        output code may slightly changed by removing *unnecessary* line breaks.
    """
    body: t.List[ast.stmt]
    code: str
    module: t.Union[ast.AST, ast.Module]
    out: str
    target_func: t.Union[ast.stmt, ast.FunctionDef]
    
    code = inspect.getsource(func)
    if strip_decorators or strip_signature:
        module = ast.parse(code)
        target_func = module.body[0]
        if strip_decorators:
            target_func.decorator_list.clear()
        if strip_return:
            # FIXME: support only stripping final-line return
            if target_func.body and isinstance(
                    target_func.body[-1],
                    ast.Return
            ):
                target_func.body.pop()
        if strip_signature:
            body = target_func.body
            out = unparse(body)
        else:
            out = unparse(target_func)
    else:
        out = code
    return out.strip()

Test

import lk_logger
from get_func_source import get_source
 
lk_logger.setup(
    show_source=False,
    show_funcname=False,
)
 
def decor(func):
    return func
 
@decor
def aaa(
    bbb: int,
    ccc: bool = False,
) -> tuple:
    print(bbb)
    print(ccc)
    return (
        bbb,
        ccc,
    )
 
if __name__ == '__main__':
    print(':di', 'source code')
    print(get_source(aaa, strip_decorators=False))
    print(':di', 'strip decorators')
    print(get_source(aaa, strip_decorators=True))
    print(':di', 'body only')
    print(get_source(aaa, strip_decorators=True, body_only=True))

the output: