Skip to content

Commit 249b70e

Browse files
committed
allow Parameter to be acception by autocompletion functions, also pass through CompletionItem return values, fix args to match what it was in click 7
1 parent e17a0f5 commit 249b70e

File tree

10 files changed

+49
-16
lines changed

10 files changed

+49
-16
lines changed

docs_src/options_autocompletion/tutorial009.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import List
22

33
import typer
4+
from click.core import Parameter
45
from rich.console import Console
56

67
valid_completion_items = [
@@ -12,9 +13,8 @@
1213
err_console = Console(stderr=True)
1314

1415

15-
def complete_name(ctx: typer.Context, args: List[str], incomplete: str):
16-
err_console.print(f"{args}")
17-
names = ctx.params.get("name") or []
16+
def complete_name(ctx: typer.Context, param: Parameter, incomplete: str):
17+
names = ctx.params.get(param.name) or []
1818
for name, help_text in valid_completion_items:
1919
if name.startswith(incomplete) and name not in names:
2020
yield (name, help_text)

docs_src/options_autocompletion/tutorial009_an.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import List
22

33
import typer
4+
from click.core import Parameter
45
from rich.console import Console
56
from typing_extensions import Annotated
67

@@ -13,9 +14,8 @@
1314
err_console = Console(stderr=True)
1415

1516

16-
def complete_name(ctx: typer.Context, args: List[str], incomplete: str):
17-
err_console.print(f"{args}")
18-
names = ctx.params.get("name") or []
17+
def complete_name(ctx: typer.Context, param: Parameter, incomplete: str):
18+
names = ctx.params.get(param.name) or []
1919
for name, help_text in valid_completion_items:
2020
if name.startswith(incomplete) and name not in names:
2121
yield (name, help_text)

tests/test_others.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def test_completion_untyped_parameters():
173173
},
174174
)
175175
assert "info name is: completion_no_types.py" in result.stderr
176-
assert "args is: []" in result.stderr
176+
assert "args is: ['--name', 'Sebastian', '--name']" in result.stderr
177177
assert "incomplete is: Ca" in result.stderr
178178
assert '"Camila":"The reader of books."' in result.stdout
179179
assert '"Carlos":"The writer of scripts."' in result.stdout
@@ -199,7 +199,7 @@ def test_completion_untyped_parameters_different_order_correct_names():
199199
},
200200
)
201201
assert "info name is: completion_no_types_order.py" in result.stderr
202-
assert "args is: []" in result.stderr
202+
assert "args is: ['--name', 'Sebastian', '--name']" in result.stderr
203203
assert "incomplete is: Ca" in result.stderr
204204
assert '"Camila":"The reader of books."' in result.stdout
205205
assert '"Carlos":"The writer of scripts."' in result.stdout

tests/test_tutorial/test_options_autocompletion/test_tutorial008.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_completion():
2323
assert '"Camila":"The reader of books."' in result.stdout
2424
assert '"Carlos":"The writer of scripts."' in result.stdout
2525
assert '"Sebastian":"The type hints guy."' in result.stdout
26-
assert "[]" in result.stderr
26+
assert "--name" in result.stderr
2727

2828

2929
def test_1():

tests/test_tutorial/test_options_autocompletion/test_tutorial008_an.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_completion():
2323
assert '"Camila":"The reader of books."' in result.stdout
2424
assert '"Carlos":"The writer of scripts."' in result.stdout
2525
assert '"Sebastian":"The type hints guy."' in result.stdout
26-
assert "[]" in result.stderr
26+
assert "--name" in result.stderr
2727

2828

2929
def test_1():

tests/test_tutorial/test_options_autocompletion/test_tutorial009.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ def test_completion():
2323
assert '"Camila":"The reader of books."' in result.stdout
2424
assert '"Carlos":"The writer of scripts."' in result.stdout
2525
assert '"Sebastian":"The type hints guy."' not in result.stdout
26-
assert "[]" in result.stderr
2726

2827

2928
def test_1():

tests/test_tutorial/test_options_autocompletion/test_tutorial009_an.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ def test_completion():
2323
assert '"Camila":"The reader of books."' in result.stdout
2424
assert '"Carlos":"The writer of scripts."' in result.stdout
2525
assert '"Sebastian":"The type hints guy."' not in result.stdout
26-
assert "[]" in result.stderr
2726

2827

2928
def test_1():

typer/_completion_classes.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ def get_completion_args(self) -> Tuple[List[str], str]:
4242
except IndexError:
4343
incomplete = ""
4444

45+
obj = self.ctx_args.setdefault("obj", {})
46+
if isinstance(obj, dict):
47+
obj.setdefault("args", args)
4548
return args, incomplete
4649

4750
def format_completion(self, item: click.shell_completion.CompletionItem) -> str:
@@ -77,6 +80,11 @@ def get_completion_args(self) -> Tuple[List[str], str]:
7780
args = args[:-1]
7881
else:
7982
incomplete = ""
83+
84+
obj = self.ctx_args.setdefault("obj", {})
85+
if isinstance(obj, dict):
86+
obj.setdefault("args", args)
87+
8088
return args, incomplete
8189

8290
def format_completion(self, item: click.shell_completion.CompletionItem) -> str:
@@ -127,6 +135,11 @@ def get_completion_args(self) -> Tuple[List[str], str]:
127135
args = args[:-1]
128136
else:
129137
incomplete = ""
138+
139+
obj = self.ctx_args.setdefault("obj", {})
140+
if isinstance(obj, dict):
141+
obj.setdefault("args", args)
142+
130143
return args, incomplete
131144

132145
def format_completion(self, item: click.shell_completion.CompletionItem) -> str:
@@ -176,6 +189,11 @@ def get_completion_args(self) -> Tuple[List[str], str]:
176189
incomplete = os.getenv("_TYPER_COMPLETE_WORD_TO_COMPLETE", "")
177190
cwords = click.parser.split_arg_string(completion_args)
178191
args = cwords[1:-1] if incomplete else cwords[1:]
192+
193+
obj = self.ctx_args.setdefault("obj", {})
194+
if isinstance(obj, dict):
195+
obj.setdefault("args", args)
196+
179197
return args, incomplete
180198

181199
def format_completion(self, item: click.shell_completion.CompletionItem) -> str:

typer/core.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ def _typer_param_setup_autocompletion_compat(
5959
self: click.Parameter,
6060
*,
6161
autocompletion: Optional[
62-
Callable[[click.Context, List[str], str], List[Union[Tuple[str, str], str]]]
62+
Callable[
63+
[click.Context, click.core.Parameter, str],
64+
List[Union[Tuple[str, str], str, "click.shell_completion.CompletionItem"]],
65+
]
6366
] = None,
6467
) -> None:
6568
if self._custom_shell_complete is not None:
@@ -81,9 +84,11 @@ def compat_autocompletion(
8184

8285
out = []
8386

84-
for c in autocompletion(ctx, [], incomplete):
87+
for c in autocompletion(ctx, param, incomplete):
8588
if isinstance(c, tuple):
8689
use_completion = CompletionItem(c[0], help=c[1])
90+
elif isinstance(c, CompletionItem):
91+
use_completion = c
8792
else:
8893
assert isinstance(c, str)
8994
use_completion = CompletionItem(c)

typer/main.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,7 @@ def get_param_completion(
10301030
parameters = get_params_from_function(callback)
10311031
ctx_name = None
10321032
args_name = None
1033+
param_name = None
10331034
incomplete_name = None
10341035
unassigned_params = list(parameters.values())
10351036
for param_sig in unassigned_params[:]:
@@ -1040,6 +1041,9 @@ def get_param_completion(
10401041
elif lenient_issubclass(origin, List):
10411042
args_name = param_sig.name
10421043
unassigned_params.remove(param_sig)
1044+
elif lenient_issubclass(param_sig.annotation, click.core.Parameter):
1045+
param_name = param_sig.name
1046+
unassigned_params.remove(param_sig)
10431047
elif lenient_issubclass(param_sig.annotation, str):
10441048
incomplete_name = param_sig.name
10451049
unassigned_params.remove(param_sig)
@@ -1051,6 +1055,9 @@ def get_param_completion(
10511055
elif args_name is None and param_sig.name == "args":
10521056
args_name = param_sig.name
10531057
unassigned_params.remove(param_sig)
1058+
elif param_name is None and param_sig.name == "param":
1059+
param_name = param_sig.name
1060+
unassigned_params.remove(param_sig)
10541061
elif incomplete_name is None and param_sig.name == "incomplete":
10551062
incomplete_name = param_sig.name
10561063
unassigned_params.remove(param_sig)
@@ -1061,12 +1068,17 @@ def get_param_completion(
10611068
f"Invalid autocompletion callback parameters: {show_params}"
10621069
)
10631070

1064-
def wrapper(ctx: click.Context, args: List[str], incomplete: Optional[str]) -> Any:
1071+
def wrapper(
1072+
ctx: click.Context, param: click.core.Parameter, incomplete: Optional[str]
1073+
) -> Any:
10651074
use_params: Dict[str, Any] = {}
10661075
if ctx_name:
10671076
use_params[ctx_name] = ctx
10681077
if args_name:
1069-
use_params[args_name] = args
1078+
obj = ctx.obj or {}
1079+
use_params[args_name] = obj.get("args", []) if isinstance(obj, dict) else []
1080+
if param_name:
1081+
use_params[param_name] = param
10701082
if incomplete_name:
10711083
use_params[incomplete_name] = incomplete
10721084
return callback(**use_params)

0 commit comments

Comments
 (0)