forked from fastapi/typer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompletion.py
159 lines (130 loc) · 4.84 KB
/
completion.py
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import os
import sys
from typing import Any, Dict, Tuple
import click
from ._completion_shared import Shells, get_completion_script, install
from .models import ParamMeta
from .params import Option
from .utils import _get_click_major, get_params_from_function
try:
import shellingham
except ImportError: # pragma: nocover
shellingham = None
_click_patched = False
def get_completion_inspect_parameters() -> Tuple[ParamMeta, ParamMeta]:
completion_init()
test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION")
if shellingham and not test_disable_detection:
parameters = get_params_from_function(_install_completion_placeholder_function)
else:
parameters = get_params_from_function(
_install_completion_no_auto_placeholder_function
)
install_param, show_param = parameters.values()
return install_param, show_param
def install_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
if not value or ctx.resilient_parsing:
return value # pragma no cover
if isinstance(value, str):
shell, path = install(shell=value)
else:
shell, path = install()
click.secho(f"{shell} completion installed in {path}", fg="green")
click.echo("Completion will take effect once you restart the terminal")
sys.exit(0)
def show_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
if not value or ctx.resilient_parsing:
return value # pragma no cover
prog_name = ctx.find_root().info_name
assert prog_name
complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper())
shell = ""
test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION")
if isinstance(value, str):
shell = value
elif shellingham and not test_disable_detection:
shell, _ = shellingham.detect_shell()
script_content = get_completion_script(
prog_name=prog_name, complete_var=complete_var, shell=shell
)
click.echo(script_content)
sys.exit(0)
# Create a fake command function to extract the completion parameters
def _install_completion_placeholder_function(
install_completion: bool = Option(
None,
"--install-completion",
is_flag=True,
callback=install_callback,
expose_value=False,
help="Install completion for the current shell.",
),
show_completion: bool = Option(
None,
"--show-completion",
is_flag=True,
callback=show_callback,
expose_value=False,
help="Show completion for the current shell, to copy it or customize the installation.",
),
) -> Any:
pass # pragma no cover
def _install_completion_no_auto_placeholder_function(
install_completion: Shells = Option(
None,
callback=install_callback,
expose_value=False,
help="Install completion for the specified shell.",
),
show_completion: Shells = Option(
None,
callback=show_callback,
expose_value=False,
help="Show completion for the specified shell, to copy it or customize the installation.",
),
) -> Any:
pass # pragma no cover
def completion_init() -> None:
if _get_click_major() < 8:
from ._completion_click7 import completion_init
completion_init()
else:
from ._completion_click8 import completion_init
completion_init()
# Re-implement Click's shell_complete to add error message with:
# Invalid completion instruction
# To use 7.x instruction style for compatibility
# And to add extra error messages, for compatibility with Typer in previous versions
# This is only called in new Command method, only used by Click 8.x+
def shell_complete(
cli: click.BaseCommand,
ctx_args: Dict[str, Any],
prog_name: str,
complete_var: str,
instruction: str,
) -> int:
import click
import click.shell_completion
if "_" not in instruction:
click.echo("Invalid completion instruction.", err=True)
return 1
# Click 8 changed the order/style of shell instructions from e.g.
# source_bash to bash_source
# Typer override to preserve the old style for compatibility
# Original in Click 8.x commented:
# shell, _, instruction = instruction.partition("_")
instruction, _, shell = instruction.partition("_")
# Typer override end
comp_cls = click.shell_completion.get_completion_class(shell)
if comp_cls is None:
click.echo(f"Shell {shell} not supported.", err=True)
return 1
comp = comp_cls(cli, ctx_args, prog_name, complete_var)
if instruction == "source":
click.echo(comp.source())
return 0
if instruction == "complete":
click.echo(comp.complete())
return 0
click.echo(f'Completion instruction "{instruction}" not supported.', err=True)
return 1