File: monkey.py

package info (click to toggle)
python-click-threading 0.5.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 152 kB
  • sloc: python: 344; makefile: 200; sh: 7
file content (84 lines) | stat: -rw-r--r-- 2,334 bytes parent folder | download
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# -*- coding: utf-8 -*-

import types
import contextlib
import inspect

from ._compat import PY2, getargspec


class FunctionInfo(object):
    def __init__(self, interactive):
        self.interactive = interactive


_ui_functions = {
    'echo_via_pager': FunctionInfo(interactive=True),
    'prompt': FunctionInfo(interactive=True),
    'confirm': FunctionInfo(interactive=True),
    'clear': FunctionInfo(interactive=False),
    'echo': FunctionInfo(interactive=False),
    'edit': FunctionInfo(interactive=True),
    'launch': FunctionInfo(interactive=True),
    'getchar': FunctionInfo(interactive=True),
    'pause': FunctionInfo(interactive=True),
}


@contextlib.contextmanager
def patch_ui_functions(wrapper):
    '''Wrap all termui functions with a custom decorator.'''
    NONE = object()
    import click

    saved = []

    for name, info in sorted(_ui_functions.items()):
        f = getattr(click, name, NONE)
        if f is NONE:
            continue

        new_f = wrapper(_copy_fn(f), info)

        orig_sig_obj = inspect.signature(f)
        sig_obj = orig_sig_obj.replace(
            parameters=[
                p.replace(annotation=inspect.Parameter.empty)
                for p in orig_sig_obj.parameters.values()
            ],
            return_annotation=inspect.Signature.empty,
        )
        signature = str(sig_obj).lstrip('(').rstrip(')')
        args = ', '.join(p for p in sig_obj.parameters.keys())

        stub_f = eval('lambda {s}: {n}._real_click_fn({a})'
                      .format(n=f.__name__, s=signature, a=args))

        if PY2:
            saved.append((f, f.func_code))
            f.func_code = stub_f.func_code
        else:
            saved.append((f, f.__code__))
            f.__code__ = stub_f.__code__

        f._real_click_fn = new_f

    try:
        yield
    finally:
        for f, code in saved:
            if PY2:
                f.func_code = code
            else:
                f.__code__ = code

            del f._real_click_fn


def _copy_fn(f):
    if PY2:
        return types.FunctionType(f.func_code, f.func_globals, f.func_name,
                                  f.func_defaults, f.func_closure)
    else:
        return types.FunctionType(f.__code__, f.__globals__, f.__name__,
                                  f.__defaults__, f.__closure__)