Skip to content
Merged
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
10 changes: 10 additions & 0 deletions Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
Change history
================

.. _version-unreleased:

Unreleased
==========

- Do not offer true/false value completions for boolean flags (``is_flag=True``,
including ``--foo/--no-foo`` style options), which previously inserted a value
into the positional-argument slot (#116).


.. _version-0.3.0:

0.3.0
Expand Down
8 changes: 7 additions & 1 deletion click_repl/_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,13 @@ def _get_completion_from_params(
choices: list[Completion] = []
param_type = param.type

# shell_complete method for click.Choice is intorduced in click-v8
# Flags (is_flag=True, incl. secondary opts like --foo/--no-foo) do not
# consume a value, so we must not offer any value completions for them.
# See https://github.com/click-contrib/click-repl/issues/116
if getattr(param, "is_flag", False):
return choices

# shell_complete method for click.Choice was introduced in Click v8
if not HAS_CLICK_V8 and isinstance(param_type, click.Choice):
choices.extend(
self._get_completion_from_choices_click_le_7(param, incomplete)
Expand Down
32 changes: 32 additions & 0 deletions tests/test_completion/test_common_tests/test_option_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,38 @@ def bool_option(foo):
assert {x.text for x in completions} == {"true"}


def test_flag_option_offers_no_value():
# A flag (is_flag=True) does not consume a value, so once it has been
# typed the completer must not offer true/false as if it needed one.
# See https://github.com/click-contrib/click-repl/issues/116
@root_command.command()
@click.argument("arg1", type=click.STRING)
@click.option("-b", "--some-option", "some_option", is_flag=True)
def flag_option(arg1, some_option):
pass

completions = list(c.get_completions(Document("flag-option -b ")))
assert {x.text for x in completions} == set()

completions = list(c.get_completions(Document("flag-option --some-option ")))
assert {x.text for x in completions} == set()


def test_boolean_flag_with_secondary_opts_offers_no_value():
# Flags declared with a secondary option (--foo/--no-foo) are also flags
# and must not trigger true/false value completions.
@root_command.command()
@click.option("--shout/--no-shout", default=False)
def toggle_flag(shout):
pass

completions = list(c.get_completions(Document("toggle-flag --shout ")))
assert {x.text for x in completions} == set()

completions = list(c.get_completions(Document("toggle-flag --no-shout ")))
assert {x.text for x in completions} == set()


def test_only_unused_with_unique_option():
@root_command.command()
@click.option("-u", type=click.BOOL)
Expand Down