-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Summary
In Click 8.2.0, completion for commands in nested groups doesn't work as expected anymore. Instead of completing command options and/or arguments, completion infinitely repeats the command names for the group.
Example program
Inspired by the example in #2847
Save the following as bin/nested
in a virtualenv
#!/usr/bin/env python
# nested
import click
def _complete_arg(ctx, _, incomplete):
values = [
"foo",
"bar",
"foobar",
"baz",
]
return [v for v in values if v.startswith(incomplete)]
@click.group
def main():
...
@main.group
def subgroup():
...
@subgroup.command
@click.option("--name", help="Name of something.")
@click.argument("arg", shell_complete=_complete_arg)
def compile(name: str | None, arg: str) -> None:
"""Test argument completion in nested groups."""
click.echo(f"{name=} {arg=}")
if __name__ == "__main__":
main.main()
Run eval "$(_NESTED_COMPLETE=bash_source nested)"
to setup completion (for bash)
Completion behavior
Prefix | 8.2.0 completion suggestions (unexpected behavior) | 8.1.8 completion suggestions (expected behavior) |
---|---|---|
nested |
subgroup |
subgroup |
nested subgroup |
compile |
compile |
nested subgroup compile |
compile |
foo bar foobar baz |
nested subgroup compile f |
none | foo foobar |
nested subgroup compile -- |
--help |
--name --help |
nested subgroup compile --name=n |
compile |
foo bar foobar baz |
Environment
- Python version: Python 3.12.3
- Click version: 8.2.0
Initial debugging
Reverting 0ef55fd for src/click/shell_completion.py
restores the 8.1.8 completion behavior.
Looking at the change, I believe that the bug is actually caused by a simple statement reordering . IMO
click/src/click/shell_completion.py
Lines 567 to 571 in af73ce4
with cmd.make_context( | |
name, args, parent=ctx, resilient_parsing=True | |
) as sub_ctx: | |
args = ctx._protected_args + ctx.args | |
ctx = sub_ctx |
with cmd.make_context(
name, args, parent=ctx, resilient_parsing=True
) as sub_ctx:
ctx = sub_ctx
args = ctx._protected_args + ctx.args
Note that Click 8.1.8 directly assigns cmd.make_context()
to ctx
in the equivalent snippet:
click/src/click/shell_completion.py
Lines 530 to 531 in 934813e
ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) | |
args = ctx.protected_args + ctx.args |
In the same fashion, I believe that lines 589 and 590 should be switched in
click/src/click/shell_completion.py
Lines 581 to 590 in af73ce4
with cmd.make_context( | |
name, | |
args, | |
parent=ctx, | |
allow_extra_args=True, | |
allow_interspersed_args=False, | |
resilient_parsing=True, | |
) as sub_sub_ctx: | |
args = sub_ctx.args | |
sub_ctx = sub_sub_ctx |