def get_func_sourcecode(func):
    """
    Try to get sourcecode using standard inspect.getsource().
    If the function comes from a module which has been created dynamically
    (not from the filesystem), then it tries to read the sourcecode on the
    filesystem anyway.
    WARNING: can do weird things if the filesystem code slightly differs from
             the original module code.
    """

    def getsource(func):
        lines, lnum = getsourcelines(func)
        return ''.join(lines)

    def getsourcelines(func):
        lines, lnum = findsource(func)
        return inspect.getblock(lines[lnum:]), lnum + 1

    def findsource(func):
        file = getfile(func)  # file path
        module = inspect.getmodule(func, file)
        lines = linecache.getlines(file, module.__dict__)
        code = func.__code__
        lnum = code.co_firstlineno - 1
        pat = re.compile(r'^(\s*def\s)|(\s*async\s+def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
        while lnum > 0:
            if pat.match(lines[lnum]):
                break
            lnum = lnum - 1  # pragma: no cover
        return lines, lnum

    def getfile(func):
        module = inspect.getmodule(func)
        return module.__file__

    try:
        return inspect.getsource(func)
    except Exception:
        return getsource(func)