Coverage for typer/completion.py: 100%

65 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-12-19 20:29 +0000

1import os 1abcdefghi

2import sys 1abcdefghi

3from typing import Any, MutableMapping, Tuple 1abcdefghi

4 

5import click 1abcdefghi

6 

7from ._completion_classes import completion_init 1abcdefghi

8from ._completion_shared import Shells, _get_shell_name, get_completion_script, install 1abcdefghi

9from .core import HAS_SHELLINGHAM 1abcdefghi

10from .models import ParamMeta 1abcdefghi

11from .params import Option 1abcdefghi

12from .utils import get_params_from_function 1abcdefghi

13 

14_click_patched = False 1abcdefghi

15 

16 

17def get_completion_inspect_parameters() -> Tuple[ParamMeta, ParamMeta]: 1abcdefghi

18 completion_init() 1abcdefghi

19 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 1abcdefghi

20 if HAS_SHELLINGHAM and not test_disable_detection: 1abcdefghi

21 parameters = get_params_from_function(_install_completion_placeholder_function) 1abcdefghi

22 else: 

23 parameters = get_params_from_function( 1abcdefghi

24 _install_completion_no_auto_placeholder_function 

25 ) 

26 install_param, show_param = parameters.values() 1abcdefghi

27 return install_param, show_param 1abcdefghi

28 

29 

30def install_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 1abcdefghi

31 if not value or ctx.resilient_parsing: 1abcdefghi

32 return value # pragma: no cover 1abcdefghi

33 if isinstance(value, str): 1abcdefghi

34 shell, path = install(shell=value) 1abcdefghi

35 else: 

36 shell, path = install() 1abcdefghi

37 click.secho(f"{shell} completion installed in {path}", fg="green") 1abcdefghi

38 click.echo("Completion will take effect once you restart the terminal") 1abcdefghi

39 sys.exit(0) 1abcdefghi

40 

41 

42def show_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 1abcdefghi

43 if not value or ctx.resilient_parsing: 1abcdefghi

44 return value # pragma: no cover 1abcdefghi

45 prog_name = ctx.find_root().info_name 1abcdefghi

46 assert prog_name 1abcdefghi

47 complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper()) 1abcdefghi

48 shell = "" 1abcdefghi

49 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 1abcdefghi

50 if isinstance(value, str): 1abcdefghi

51 shell = value 1abcdefghi

52 elif not test_disable_detection: 1abcdefghi

53 detected_shell = _get_shell_name() 1abcdefghi

54 if detected_shell is not None: 1abcdefghi

55 shell = detected_shell 1abcdefghi

56 script_content = get_completion_script( 1abcdefghi

57 prog_name=prog_name, complete_var=complete_var, shell=shell 

58 ) 

59 click.echo(script_content) 1abcdefghi

60 sys.exit(0) 1abcdefghi

61 

62 

63# Create a fake command function to extract the completion parameters 

64def _install_completion_placeholder_function( 1abcdefghi

65 install_completion: bool = Option( 

66 None, 

67 "--install-completion", 

68 callback=install_callback, 

69 expose_value=False, 

70 help="Install completion for the current shell.", 

71 ), 

72 show_completion: bool = Option( 

73 None, 

74 "--show-completion", 

75 callback=show_callback, 

76 expose_value=False, 

77 help="Show completion for the current shell, to copy it or customize the installation.", 

78 ), 

79) -> Any: 

80 pass # pragma: no cover 

81 

82 

83def _install_completion_no_auto_placeholder_function( 1abcdefghi

84 install_completion: Shells = Option( 

85 None, 

86 callback=install_callback, 

87 expose_value=False, 

88 help="Install completion for the specified shell.", 

89 ), 

90 show_completion: Shells = Option( 

91 None, 

92 callback=show_callback, 

93 expose_value=False, 

94 help="Show completion for the specified shell, to copy it or customize the installation.", 

95 ), 

96) -> Any: 

97 pass # pragma: no cover 

98 

99 

100# Re-implement Click's shell_complete to add error message with: 

101# Invalid completion instruction 

102# To use 7.x instruction style for compatibility 

103# And to add extra error messages, for compatibility with Typer in previous versions 

104# This is only called in new Command method, only used by Click 8.x+ 

105def shell_complete( 1abcdefghi

106 cli: click.Command, 

107 ctx_args: MutableMapping[str, Any], 

108 prog_name: str, 

109 complete_var: str, 

110 instruction: str, 

111) -> int: 

112 import click 1abcdefghi

113 import click.shell_completion 1abcdefghi

114 

115 if "_" not in instruction: 1abcdefghi

116 click.echo("Invalid completion instruction.", err=True) 1abcdefghi

117 return 1 1abcdefghi

118 

119 # Click 8 changed the order/style of shell instructions from e.g. 

120 # source_bash to bash_source 

121 # Typer override to preserve the old style for compatibility 

122 # Original in Click 8.x commented: 

123 # shell, _, instruction = instruction.partition("_") 

124 instruction, _, shell = instruction.partition("_") 1abcdefghi

125 # Typer override end 

126 

127 comp_cls = click.shell_completion.get_completion_class(shell) 1abcdefghi

128 

129 if comp_cls is None: 1abcdefghi

130 click.echo(f"Shell {shell} not supported.", err=True) 1abcdefghi

131 return 1 1abcdefghi

132 

133 comp = comp_cls(cli, ctx_args, prog_name, complete_var) 1abcdefghi

134 

135 if instruction == "source": 1abcdefghi

136 click.echo(comp.source()) 1abcdefghi

137 return 0 1abcdefghi

138 

139 # Typer override to print the completion help msg with Rich 

140 if instruction == "complete": 1abcdefghi

141 click.echo(comp.complete()) 1abcdefghi

142 return 0 1abcdefghi

143 # Typer override end 

144 

145 click.echo(f'Completion instruction "{instruction}" not supported.', err=True) 1abcdefghi

146 return 1 1abcdefghi