aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Automat/py3/automat/_introspection.py
blob: e433b2f9f9f7ed7283d61f77f63e4513cd22796e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
"""
Python introspection helpers.
"""

from types import CodeType as code, FunctionType as function


def copycode(template, changes):
    if hasattr(code, "replace"):
        return template.replace(**{"co_" + k: v for k, v in changes.items()})
    names = [
        "argcount",
        "nlocals",
        "stacksize",
        "flags",
        "code",
        "consts",
        "names",
        "varnames",
        "filename",
        "name",
        "firstlineno",
        "lnotab",
        "freevars",
        "cellvars",
    ]
    if hasattr(code, "co_kwonlyargcount"):
        names.insert(1, "kwonlyargcount")
    if hasattr(code, "co_posonlyargcount"):
        # PEP 570 added "positional only arguments"
        names.insert(1, "posonlyargcount")
    values = [changes.get(name, getattr(template, "co_" + name)) for name in names]
    return code(*values)


def copyfunction(template, funcchanges, codechanges):
    names = [
        "globals",
        "name",
        "defaults",
        "closure",
    ]
    values = [
        funcchanges.get(name, getattr(template, "__" + name + "__")) for name in names
    ]
    return function(copycode(template.__code__, codechanges), *values)


def preserveName(f):
    """
    Preserve the name of the given function on the decorated function.
    """

    def decorator(decorated):
        return copyfunction(decorated, dict(name=f.__name__), dict(name=f.__name__))

    return decorator