Skip to content
Closed

AI spam #3536

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Unreleased
tabs in option help text are now escaped, keeping the original completion
format while still supporting multi-line help. :issue:`3502`
:issue:`3043` :pr:`3504` :pr:`3508`
- Shell completion no longer evaluates parameter defaults or callbacks while
parsing completed arguments. :issue:`2614`
- Deprecated commands and options with empty or missing help text no longer
render a stray leading space before the ``(DEPRECATED)`` label. :pr:`3509`
- A :class:`Group` with ``invoke_without_command=True`` marks its subcommand as
Expand Down
8 changes: 4 additions & 4 deletions src/click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2386,7 +2386,7 @@ def consume_value(
value = envvar_value
source = ParameterSource.ENVIRONMENT

if value is UNSET:
if value is UNSET and not ctx.resilient_parsing:
default_map_value = ctx.lookup_default(self.name)
if default_map_value is not None or ctx._default_map_has(self.name):
value = default_map_value
Expand All @@ -2397,7 +2397,7 @@ def consume_value(
if isinstance(value, str) and self.nargs != 1:
value = self.type.split_envvar_value(value)

if value is UNSET:
if value is UNSET and not ctx.resilient_parsing:
default_value = self.get_default(ctx)
if default_value is not UNSET:
value = default_value
Expand Down Expand Up @@ -2506,7 +2506,7 @@ def process_value(self, ctx: Context, value: t.Any) -> t.Any:
if self.required and self.value_is_missing(value):
raise MissingParameter(ctx=ctx, param=self)

if self.callback is not None:
if self.callback is not None and not ctx.resilient_parsing:
# Legacy case: UNSET is not exposed directly to the callback, but converted
# to None.
if value is UNSET:
Expand Down Expand Up @@ -3449,7 +3449,7 @@ def process_value(self, ctx: Context, value: t.Any) -> t.Any:
if self.is_flag and not self.required and self.is_bool_flag and value is UNSET:
value = False

if self.callback is not None:
if self.callback is not None and not ctx.resilient_parsing:
value = self.callback(ctx, self, value)

return value
Expand Down
45 changes: 45 additions & 0 deletions tests/test_shell_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,51 @@ def test_argument_default():
assert _get_words(cli, ["x"], "b") == ["b"]


def test_completion_skips_defaults_and_callbacks():
calls = []

def default():
calls.append("default")
return "value"

def callback(ctx, param, value):
calls.append(f"callback:{value}")
return value

cli = Command(
"cli",
params=[
Option(["--name"], default=default, callback=callback),
Argument(["arg"], type=Choice(["a"])),
],
)

assert _get_words(cli, [], "") == ["a"]
assert calls == []

assert _get_words(cli, ["--name", "value"], "") == ["a"]
assert calls == []


def test_completion_skips_flag_callback_for_missing_value():
calls = []

def callback(ctx, param, value):
calls.append(value)
return value

cli = Command(
"cli",
params=[
Option(["--flag"], is_flag=True, callback=callback),
Argument(["arg"], type=Choice(["a"])),
],
)

assert _get_words(cli, [], "") == ["a"]
assert calls == []


def test_type_choice():
cli = Command("cli", params=[Option(["-c"], type=Choice(["a1", "a2", "b"]))])
assert _get_words(cli, ["-c"], "") == ["a1", "a2", "b"]
Expand Down
Loading