Coverage for typer/completion.py: 100%

64 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-04-14 00:18 +0000

1import os 1iabcdefgh

2import sys 1iabcdefgh

3from typing import Any, MutableMapping, Tuple 1iabcdefgh

4 

5import click 1iabcdefgh

6 

7from ._completion_classes import completion_init 1iabcdefgh

8from ._completion_shared import Shells, get_completion_script, install 1iabcdefgh

9from .models import ParamMeta 1iabcdefgh

10from .params import Option 1iabcdefgh

11from .utils import get_params_from_function 1iabcdefgh

12 

13try: 1iabcdefgh

14 import shellingham 1iabcdefgh

15except ImportError: # pragma: no cover 

16 shellingham = None 

17 

18 

19_click_patched = False 1iabcdefgh

20 

21 

22def get_completion_inspect_parameters() -> Tuple[ParamMeta, ParamMeta]: 1iabcdefgh

23 completion_init() 1iabcdefgh

24 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 1iabcdefgh

25 if shellingham and not test_disable_detection: 1iabcdefgh

26 parameters = get_params_from_function(_install_completion_placeholder_function) 1iabcdefgh

27 else: 

28 parameters = get_params_from_function( 1iabcdefgh

29 _install_completion_no_auto_placeholder_function 

30 ) 

31 install_param, show_param = parameters.values() 1iabcdefgh

32 return install_param, show_param 1iabcdefgh

33 

34 

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

36 if not value or ctx.resilient_parsing: 1iabcdefgh

37 return value # pragma: no cover 1iabcdefgh

38 if isinstance(value, str): 1iabcdefgh

39 shell, path = install(shell=value) 1iabcdefgh

40 else: 

41 shell, path = install() 1iabcdefgh

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

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

44 sys.exit(0) 1iabcdefgh

45 

46 

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

48 if not value or ctx.resilient_parsing: 1iabcdefgh

49 return value # pragma: no cover 1iabcdefgh

50 prog_name = ctx.find_root().info_name 1iabcdefgh

51 assert prog_name 1iabcdefgh

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

53 shell = "" 1iabcdefgh

54 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 1iabcdefgh

55 if isinstance(value, str): 1iabcdefgh

56 shell = value 1iabcdefgh

57 elif shellingham and not test_disable_detection: 1iabcdefgh

58 shell, _ = shellingham.detect_shell() 1iabcdefgh

59 script_content = get_completion_script( 1iabcdefgh

60 prog_name=prog_name, complete_var=complete_var, shell=shell 

61 ) 

62 click.echo(script_content) 1iabcdefgh

63 sys.exit(0) 1iabcdefgh

64 

65 

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

67def _install_completion_placeholder_function( 1abcdefgh

68 install_completion: bool = Option( 

69 None, 

70 "--install-completion", 

71 callback=install_callback, 

72 expose_value=False, 

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

74 ), 

75 show_completion: bool = Option( 

76 None, 

77 "--show-completion", 

78 callback=show_callback, 

79 expose_value=False, 

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

81 ), 

82) -> Any: 

83 pass # pragma: no cover 

84 

85 

86def _install_completion_no_auto_placeholder_function( 1abcdefgh

87 install_completion: Shells = Option( 

88 None, 

89 callback=install_callback, 

90 expose_value=False, 

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

92 ), 

93 show_completion: Shells = Option( 

94 None, 

95 callback=show_callback, 

96 expose_value=False, 

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

98 ), 

99) -> Any: 

100 pass # pragma: no cover 

101 

102 

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

104# Invalid completion instruction 

105# To use 7.x instruction style for compatibility 

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

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

108def shell_complete( 1abcdefgh

109 cli: click.Command, 

110 ctx_args: MutableMapping[str, Any], 

111 prog_name: str, 

112 complete_var: str, 

113 instruction: str, 

114) -> int: 

115 import click 1iabcdefgh

116 import click.shell_completion 1iabcdefgh

117 

118 if "_" not in instruction: 1iabcdefgh

119 click.echo("Invalid completion instruction.", err=True) 1iabcdefgh

120 return 1 1iabcdefgh

121 

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

123 # source_bash to bash_source 

124 # Typer override to preserve the old style for compatibility 

125 # Original in Click 8.x commented: 

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

127 instruction, _, shell = instruction.partition("_") 1iabcdefgh

128 # Typer override end 

129 

130 comp_cls = click.shell_completion.get_completion_class(shell) 1iabcdefgh

131 

132 if comp_cls is None: 1iabcdefgh

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

134 return 1 1iabcdefgh

135 

136 comp = comp_cls(cli, ctx_args, prog_name, complete_var) 1iabcdefgh

137 

138 if instruction == "source": 1iabcdefgh

139 click.echo(comp.source()) 1iabcdefgh

140 return 0 1iabcdefgh

141 

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

143 if instruction == "complete": 1iabcdefgh

144 click.echo(comp.complete()) 1iabcdefgh

145 return 0 1iabcdefgh

146 # Typer override end 

147 

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

149 return 1 1iabcdefgh