|
1
|
|
|
""" |
|
2
|
|
|
Integration layer for Click https://click.palletsprojects.com/ |
|
3
|
|
|
""" |
|
4
|
|
|
|
|
5
|
1 |
|
from typing import Optional, List, Type, Callable |
|
6
|
|
|
|
|
7
|
1 |
|
from click import utils, decorators |
|
8
|
1 |
|
from click.core import BaseCommand |
|
9
|
|
|
|
|
10
|
1 |
|
from lagom.interfaces import ExtendableContainer, WriteableContainer |
|
11
|
|
|
|
|
12
|
|
|
|
|
13
|
1 |
|
class DecoratedCommand(BaseCommand): |
|
14
|
|
|
""" |
|
15
|
|
|
Virtual class which is returned by the lagom wrapped click command |
|
16
|
|
|
decorator |
|
17
|
|
|
""" |
|
18
|
|
|
|
|
19
|
1 |
|
plain_function: Callable |
|
20
|
|
|
|
|
21
|
|
|
|
|
22
|
1 |
|
class ClickIO: |
|
23
|
|
|
""" |
|
24
|
|
|
Provides an injectable hint for click IO if needed. |
|
25
|
|
|
""" |
|
26
|
|
|
|
|
27
|
1 |
|
@staticmethod |
|
28
|
1 |
|
def echo(message=None, file=None, nl=True, err=False, color=None): |
|
29
|
1 |
|
utils.echo(message, file, nl, err, color) |
|
30
|
|
|
|
|
31
|
1 |
|
def __getattr__(self, item): |
|
32
|
|
|
import click |
|
33
|
|
|
|
|
34
|
|
|
return getattr(click, item) |
|
35
|
|
|
|
|
36
|
|
|
|
|
37
|
1 |
|
class ClickIntegration: |
|
38
|
|
|
""" |
|
39
|
|
|
Integration between a container and click. The ClickIntegration |
|
40
|
|
|
instance provides all the same decorators and functions as click. |
|
41
|
|
|
""" |
|
42
|
|
|
|
|
43
|
1 |
|
_container: WriteableContainer |
|
44
|
|
|
|
|
45
|
1 |
|
def __init__( |
|
46
|
|
|
self, |
|
47
|
|
|
container: ExtendableContainer, |
|
48
|
|
|
execution_singletons: Optional[List[Type]] = None, |
|
49
|
|
|
): |
|
50
|
1 |
|
self._container = container.clone() |
|
51
|
1 |
|
self._container[ClickIO] = ClickIO() |
|
|
|
|
|
|
52
|
1 |
|
self._execution_singletons = execution_singletons or [] |
|
53
|
|
|
|
|
54
|
1 |
|
def command( |
|
55
|
|
|
self, name=None, cls=None, **attrs |
|
56
|
|
|
) -> Callable[[Callable], DecoratedCommand]: |
|
57
|
|
|
""" |
|
58
|
|
|
Proxies click.command but binds the function to lagom |
|
59
|
|
|
so that any arguments with lagom.injectable as a default will |
|
60
|
|
|
be injected by the container |
|
61
|
|
|
:param name: |
|
62
|
|
|
:param cls: |
|
63
|
|
|
:param attrs: |
|
64
|
|
|
:return: |
|
65
|
|
|
""" |
|
66
|
|
|
|
|
67
|
1 |
|
def _decorator(f): |
|
68
|
1 |
|
bound_f = self._container.partial(f, shared=self._execution_singletons) |
|
69
|
1 |
|
command = decorators.command(name, cls, **attrs)(bound_f) |
|
70
|
1 |
|
setattr(command, "plain_function", bound_f) |
|
71
|
1 |
|
return command |
|
72
|
|
|
|
|
73
|
1 |
|
return _decorator |
|
74
|
|
|
|
|
75
|
1 |
|
@staticmethod |
|
76
|
1 |
|
def option(*param_decls, **attrs): |
|
77
|
|
|
""" |
|
78
|
|
|
Proxies click.option |
|
79
|
|
|
:param param_decls: |
|
80
|
|
|
:param attrs: |
|
81
|
|
|
:return: |
|
82
|
|
|
""" |
|
83
|
|
|
return decorators.option(*param_decls, **attrs) |
|
84
|
|
|
|
|
85
|
1 |
|
@staticmethod |
|
86
|
1 |
|
def argument(*param_decls, **attrs): |
|
87
|
|
|
""" |
|
88
|
|
|
Proxies click.argument |
|
89
|
|
|
:param param_decls: |
|
90
|
|
|
:param attrs: |
|
91
|
|
|
:return: |
|
92
|
|
|
""" |
|
93
|
1 |
|
return decorators.argument(*param_decls, **attrs) |
|
94
|
|
|
|
|
95
|
1 |
|
def __getattr__(self, item): |
|
96
|
|
|
# Any method not explicitly code just gets passed to click |
|
97
|
1 |
|
import click |
|
98
|
|
|
|
|
99
|
|
|
return getattr(click, item) |
|
100
|
|
|
|