Coverage for typer / completion.py: 100%
66 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-02-09 12:36 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-02-09 12:36 +0000
1import os 1abcdefgh
2import sys 1abcdefgh
3from collections.abc import MutableMapping 1abcdefgh
4from typing import Any 1abcdefgh
6import click 1abcdefgh
8from ._completion_classes import completion_init 1abcdefgh
9from ._completion_shared import Shells, _get_shell_name, get_completion_script, install 1abcdefgh
10from .core import HAS_SHELLINGHAM 1abcdefgh
11from .models import ParamMeta 1abcdefgh
12from .params import Option 1abcdefgh
13from .utils import get_params_from_function 1abcdefgh
15_click_patched = False 1abcdefgh
18def get_completion_inspect_parameters() -> tuple[ParamMeta, ParamMeta]: 1abcdefgh
19 completion_init() 1abcdefgh
20 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 1abcdefgh
21 if HAS_SHELLINGHAM and not test_disable_detection: 1abcdefgh
22 parameters = get_params_from_function(_install_completion_placeholder_function) 1abcdefgh
23 else:
24 parameters = get_params_from_function( 1abcdefgh
25 _install_completion_no_auto_placeholder_function
26 )
27 install_param, show_param = parameters.values() 1abcdefgh
28 return install_param, show_param 1abcdefgh
31def install_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 1abcdefgh
32 if not value or ctx.resilient_parsing: 1abcdefgh
33 return value # pragma: no cover 1abcdefgh
34 if isinstance(value, str): 1abcdefgh
35 shell, path = install(shell=value) 1abcdefgh
36 else:
37 shell, path = install() 1abcdefgh
38 click.secho(f"{shell} completion installed in {path}", fg="green") 1abcdefgh
39 click.echo("Completion will take effect once you restart the terminal") 1abcdefgh
40 sys.exit(0) 1abcdefgh
43def show_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 1abcdefgh
44 if not value or ctx.resilient_parsing: 1abcdefgh
45 return value # pragma: no cover 1abcdefgh
46 prog_name = ctx.find_root().info_name 1abcdefgh
47 assert prog_name 1abcdefgh
48 complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper()) 1abcdefgh
49 shell = "" 1abcdefgh
50 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 1abcdefgh
51 if isinstance(value, str): 1abcdefgh
52 shell = value 1abcdefgh
53 elif not test_disable_detection: 1abcdefgh
54 detected_shell = _get_shell_name() 1abcdefgh
55 if detected_shell is not None: 1abcdefgh
56 shell = detected_shell 1abcdefgh
57 script_content = get_completion_script( 1abcdefgh
58 prog_name=prog_name, complete_var=complete_var, shell=shell
59 )
60 click.echo(script_content) 1abcdefgh
61 sys.exit(0) 1abcdefgh
64# Create a fake command function to extract the completion parameters
65def _install_completion_placeholder_function( 1abcdefgh
66 install_completion: bool = Option(
67 None,
68 "--install-completion",
69 callback=install_callback,
70 expose_value=False,
71 help="Install completion for the current shell.",
72 ),
73 show_completion: bool = Option(
74 None,
75 "--show-completion",
76 callback=show_callback,
77 expose_value=False,
78 help="Show completion for the current shell, to copy it or customize the installation.",
79 ),
80) -> Any:
81 pass # pragma: no cover
84def _install_completion_no_auto_placeholder_function( 1abcdefgh
85 install_completion: Shells = Option(
86 None,
87 callback=install_callback,
88 expose_value=False,
89 help="Install completion for the specified shell.",
90 ),
91 show_completion: Shells = Option(
92 None,
93 callback=show_callback,
94 expose_value=False,
95 help="Show completion for the specified shell, to copy it or customize the installation.",
96 ),
97) -> Any:
98 pass # pragma: no cover
101# Re-implement Click's shell_complete to add error message with:
102# Invalid completion instruction
103# To use 7.x instruction style for compatibility
104# And to add extra error messages, for compatibility with Typer in previous versions
105# This is only called in new Command method, only used by Click 8.x+
106def shell_complete( 1abcdefgh
107 cli: click.Command,
108 ctx_args: MutableMapping[str, Any],
109 prog_name: str,
110 complete_var: str,
111 instruction: str,
112) -> int:
113 import click 1abcdefgh
114 import click.shell_completion 1abcdefgh
116 if "_" not in instruction: 1abcdefgh
117 click.echo("Invalid completion instruction.", err=True) 1abcdefgh
118 return 1 1abcdefgh
120 # Click 8 changed the order/style of shell instructions from e.g.
121 # source_bash to bash_source
122 # Typer override to preserve the old style for compatibility
123 # Original in Click 8.x commented:
124 # shell, _, instruction = instruction.partition("_")
125 instruction, _, shell = instruction.partition("_") 1abcdefgh
126 # Typer override end
128 comp_cls = click.shell_completion.get_completion_class(shell) 1abcdefgh
130 if comp_cls is None: 1abcdefgh
131 click.echo(f"Shell {shell} not supported.", err=True) 1abcdefgh
132 return 1 1abcdefgh
134 comp = comp_cls(cli, ctx_args, prog_name, complete_var) 1abcdefgh
136 if instruction == "source": 1abcdefgh
137 click.echo(comp.source()) 1abcdefgh
138 return 0 1abcdefgh
140 # Typer override to print the completion help msg with Rich
141 if instruction == "complete": 1abcdefgh
142 click.echo(comp.complete()) 1abcdefgh
143 return 0 1abcdefgh
144 # Typer override end
146 click.echo(f'Completion instruction "{instruction}" not supported.', err=True) 1abcdefgh
147 return 1 1abcdefgh