typer.completion
1import os 2import sys 3from typing import Any, MutableMapping, Tuple 4 5import click 6 7from ._completion_classes import completion_init 8from ._completion_shared import Shells, get_completion_script, install 9from .models import ParamMeta 10from .params import Option 11from .utils import get_params_from_function 12 13try: 14 import shellingham 15except ImportError: # pragma: no cover 16 shellingham = None 17 18 19_click_patched = False 20 21 22def get_completion_inspect_parameters() -> Tuple[ParamMeta, ParamMeta]: 23 completion_init() 24 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 25 if shellingham and not test_disable_detection: 26 parameters = get_params_from_function(_install_completion_placeholder_function) 27 else: 28 parameters = get_params_from_function( 29 _install_completion_no_auto_placeholder_function 30 ) 31 install_param, show_param = parameters.values() 32 return install_param, show_param 33 34 35def install_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 36 if not value or ctx.resilient_parsing: 37 return value # pragma: no cover 38 if isinstance(value, str): 39 shell, path = install(shell=value) 40 else: 41 shell, path = install() 42 click.secho(f"{shell} completion installed in {path}", fg="green") 43 click.echo("Completion will take effect once you restart the terminal") 44 sys.exit(0) 45 46 47def show_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 48 if not value or ctx.resilient_parsing: 49 return value # pragma: no cover 50 prog_name = ctx.find_root().info_name 51 assert prog_name 52 complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper()) 53 shell = "" 54 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 55 if isinstance(value, str): 56 shell = value 57 elif shellingham and not test_disable_detection: 58 shell, _ = shellingham.detect_shell() 59 script_content = get_completion_script( 60 prog_name=prog_name, complete_var=complete_var, shell=shell 61 ) 62 click.echo(script_content) 63 sys.exit(0) 64 65 66# Create a fake command function to extract the completion parameters 67def _install_completion_placeholder_function( 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( 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( 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 116 import click.shell_completion 117 118 if "_" not in instruction: 119 click.echo("Invalid completion instruction.", err=True) 120 return 1 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("_") 128 # Typer override end 129 130 comp_cls = click.shell_completion.get_completion_class(shell) 131 132 if comp_cls is None: 133 click.echo(f"Shell {shell} not supported.", err=True) 134 return 1 135 136 comp = comp_cls(cli, ctx_args, prog_name, complete_var) 137 138 if instruction == "source": 139 click.echo(comp.source()) 140 return 0 141 142 # Typer override to print the completion help msg with Rich 143 if instruction == "complete": 144 click.echo(comp.complete()) 145 return 0 146 # Typer override end 147 148 click.echo(f'Completion instruction "{instruction}" not supported.', err=True) 149 return 1
23def get_completion_inspect_parameters() -> Tuple[ParamMeta, ParamMeta]: 24 completion_init() 25 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 26 if shellingham and not test_disable_detection: 27 parameters = get_params_from_function(_install_completion_placeholder_function) 28 else: 29 parameters = get_params_from_function( 30 _install_completion_no_auto_placeholder_function 31 ) 32 install_param, show_param = parameters.values() 33 return install_param, show_param
def
install_callback(ctx: click.core.Context, param: click.core.Parameter, value: Any) -> Any:
36def install_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 37 if not value or ctx.resilient_parsing: 38 return value # pragma: no cover 39 if isinstance(value, str): 40 shell, path = install(shell=value) 41 else: 42 shell, path = install() 43 click.secho(f"{shell} completion installed in {path}", fg="green") 44 click.echo("Completion will take effect once you restart the terminal") 45 sys.exit(0)
def
show_callback(ctx: click.core.Context, param: click.core.Parameter, value: Any) -> Any:
48def show_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any: 49 if not value or ctx.resilient_parsing: 50 return value # pragma: no cover 51 prog_name = ctx.find_root().info_name 52 assert prog_name 53 complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper()) 54 shell = "" 55 test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION") 56 if isinstance(value, str): 57 shell = value 58 elif shellingham and not test_disable_detection: 59 shell, _ = shellingham.detect_shell() 60 script_content = get_completion_script( 61 prog_name=prog_name, complete_var=complete_var, shell=shell 62 ) 63 click.echo(script_content) 64 sys.exit(0)
def
shell_complete( cli: click.core.Command, ctx_args: MutableMapping[str, Any], prog_name: str, complete_var: str, instruction: str) -> int:
109def shell_complete( 110 cli: click.Command, 111 ctx_args: MutableMapping[str, Any], 112 prog_name: str, 113 complete_var: str, 114 instruction: str, 115) -> int: 116 import click 117 import click.shell_completion 118 119 if "_" not in instruction: 120 click.echo("Invalid completion instruction.", err=True) 121 return 1 122 123 # Click 8 changed the order/style of shell instructions from e.g. 124 # source_bash to bash_source 125 # Typer override to preserve the old style for compatibility 126 # Original in Click 8.x commented: 127 # shell, _, instruction = instruction.partition("_") 128 instruction, _, shell = instruction.partition("_") 129 # Typer override end 130 131 comp_cls = click.shell_completion.get_completion_class(shell) 132 133 if comp_cls is None: 134 click.echo(f"Shell {shell} not supported.", err=True) 135 return 1 136 137 comp = comp_cls(cli, ctx_args, prog_name, complete_var) 138 139 if instruction == "source": 140 click.echo(comp.source()) 141 return 0 142 143 # Typer override to print the completion help msg with Rich 144 if instruction == "complete": 145 click.echo(comp.complete()) 146 return 0 147 # Typer override end 148 149 click.echo(f'Completion instruction "{instruction}" not supported.', err=True) 150 return 1