summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2021-07-04 07:56:52 -0700
committerDavid Lord <davidism@gmail.com>2021-07-04 07:56:52 -0700
commitce152bd7215038f762ee918e6e181a5309ad57c9 (patch)
tree7235fa389357c4cdcbf707018877a8ca6ed0f152
parentff72d7d50cae327786b73415f0f4dc348996215c (diff)
parent76cc18d1f0bd5854f14526e3ccbce631d8344cce (diff)
downloadclick-ce152bd7215038f762ee918e6e181a5309ad57c9.tar.gz
Merge remote-tracking branch 'origin/8.0.x'
-rw-r--r--CHANGES.rst8
-rw-r--r--CONTRIBUTING.rst10
-rw-r--r--docs/api.rst2
-rw-r--r--docs/utils.rst9
-rw-r--r--examples/completion/README6
-rw-r--r--examples/completion/completion.py5
-rw-r--r--src/click/core.py13
-rw-r--r--src/click/shell_completion.py13
-rw-r--r--tests/test_options.py30
-rw-r--r--tests/test_shell_completion.py8
10 files changed, 87 insertions, 17 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 3723346..3efa72a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -11,6 +11,14 @@ Version 8.0.2
Unreleased
+- ``is_bool_flag`` is not set to ``True`` if ``is_flag`` is ``False``.
+ :issue:`1925`
+- Bash version detection is locale independent. :issue:`1940`
+- Empty ``default`` value is not shown for ``multiple=True``.
+ :issue:`1969`
+- Fix shell completion for arguments that start with a forward slash
+ such as absolute file paths. :issue:`1929`
+
Version 8.0.1
-------------
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 80273eb..1ad3bdc 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -92,7 +92,7 @@ First time setup
.. code-block:: text
- git remote add fork https://github.com/{username}/click
+ $ git remote add fork https://github.com/{username}/click
- Create a virtualenv.
@@ -107,6 +107,12 @@ First time setup
> env\Scripts\activate
+- Upgrade pip and setuptools.
+
+ .. code-block:: text
+
+ $ python -m pip install --upgrade pip setuptools
+
- Install the development dependencies, then install Click in
editable mode.
@@ -138,7 +144,7 @@ Start coding
.. code-block:: text
$ git fetch origin
- $ git checkout -b your-branch-name origin/7.x
+ $ git checkout -b your-branch-name origin/8.0.x
If you're submitting a feature addition or change, branch off of the
"main" branch.
diff --git a/docs/api.rst b/docs/api.rst
index 23d6af3..5133085 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -141,6 +141,8 @@ Types
.. autoclass:: FloatRange
+.. autoclass:: DateTime
+
.. autoclass:: Tuple
.. autoclass:: ParamType
diff --git a/docs/utils.rst b/docs/utils.rst
index fb7d3c2..995c171 100644
--- a/docs/utils.rst
+++ b/docs/utils.rst
@@ -339,13 +339,18 @@ Example usage::
Showing Progress Bars
---------------------
-.. versionadded:: 2.0
-
Sometimes, you have command line scripts that need to process a lot of data,
but you want to quickly show the user some progress about how long that
will take. Click supports simple progress bar rendering for that through
the :func:`progressbar` function.
+.. note::
+
+ If you find that you have requirements beyond what Click's progress
+ bar supports, try using `tqdm`_.
+
+ .. _tqdm: https://tqdm.github.io/
+
The basic usage is very simple: the idea is that you have an iterable that
you want to operate on. For each item in the iterable it might take some
time to do processing. So say you have a loop like this::
diff --git a/examples/completion/README b/examples/completion/README
index f15654e..372b1d4 100644
--- a/examples/completion/README
+++ b/examples/completion/README
@@ -11,18 +11,18 @@ For Bash:
.. code-block:: bash
- eval "$(_COMPLETION_COMPLETE=source_bash completion)"
+ eval "$(_COMPLETION_COMPLETE=bash_source completion)"
For Zsh:
.. code-block:: zsh
- eval "$(_COMPLETION_COMPLETE=source_zsh completion)"
+ eval "$(_COMPLETION_COMPLETE=zsh_source completion)"
For Fish:
.. code-block:: fish
- eval (env _COMPLETION_COMPLETE=source_fish completion)
+ eval (env _COMPLETION_COMPLETE=fish_source completion)
Now press tab (maybe twice) after typing something to see completions.
diff --git a/examples/completion/completion.py b/examples/completion/completion.py
index abd09c0..6c45a1f 100644
--- a/examples/completion/completion.py
+++ b/examples/completion/completion.py
@@ -38,10 +38,13 @@ def list_users(ctx, param, incomplete):
# of CompletionItem. You can match on whatever you want, including
# the help.
items = [("bob", "butcher"), ("alice", "baker"), ("jerry", "candlestick maker")]
+ out = []
for value, help in items:
if incomplete in value or incomplete in help:
- yield CompletionItem(value, help=help)
+ out.append(CompletionItem(value, help=help))
+
+ return out
@group.command(help="Choose a user")
diff --git a/src/click/core.py b/src/click/core.py
index e2ccf59..34fae4b 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -2197,7 +2197,7 @@ class Parameter:
self, ctx: Context, call: bool = True
) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
"""Get the default for the parameter. Tries
- :meth:`Context.lookup_value` first, then the local default.
+ :meth:`Context.lookup_default` first, then the local default.
:param ctx: Current context.
:param call: If the default is a callable, call it. Disable to
@@ -2461,7 +2461,7 @@ class Option(Parameter):
def __init__(
self,
param_decls: t.Optional[t.Sequence[str]] = None,
- show_default: bool = False,
+ show_default: t.Union[bool, str] = False,
prompt: t.Union[bool, str] = False,
confirmation_prompt: t.Union[bool, str] = False,
prompt_required: bool = True,
@@ -2528,7 +2528,7 @@ class Option(Parameter):
self.type = types.convert_type(None, flag_value)
self.is_flag: bool = is_flag
- self.is_bool_flag = isinstance(self.type, types.BoolParamType)
+ self.is_bool_flag = is_flag and isinstance(self.type, types.BoolParamType)
self.flag_value: t.Any = flag_value
# Counting
@@ -2590,7 +2590,7 @@ class Option(Parameter):
for decl in decls:
if decl.isidentifier():
if name is not None:
- raise TypeError("Name defined twice")
+ raise TypeError(f"Name '{name}' defined twice")
name = decl
else:
split_char = ";" if decl[:1] == "/" else "/"
@@ -2748,7 +2748,8 @@ class Option(Parameter):
else:
default_string = str(default_value)
- extra.append(_("default: {default}").format(default=default_string))
+ if default_string:
+ extra.append(_("default: {default}").format(default=default_string))
if isinstance(self.type, types._NumberRangeBase):
range_str = self.type._describe_range()
@@ -2760,7 +2761,7 @@ class Option(Parameter):
extra.append(_("required"))
if extra:
- extra_str = ";".join(extra)
+ extra_str = "; ".join(extra)
help = f"{help} [{extra_str}]" if help else f"[{extra_str}]"
return ("; " if any_prefix_is_slash else " / ").join(rv), help
diff --git a/src/click/shell_completion.py b/src/click/shell_completion.py
index 706fb69..cad080d 100644
--- a/src/click/shell_completion.py
+++ b/src/click/shell_completion.py
@@ -302,8 +302,10 @@ class BashComplete(ShellComplete):
def _check_version(self) -> None:
import subprocess
- output = subprocess.run(["bash", "--version"], stdout=subprocess.PIPE)
- match = re.search(r"version (\d)\.(\d)\.\d", output.stdout.decode())
+ output = subprocess.run(
+ ["bash", "-c", "echo ${BASH_VERSION}"], stdout=subprocess.PIPE
+ )
+ match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode())
if match is not None:
major, minor = match.groups()
@@ -448,7 +450,12 @@ def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool:
def _start_of_option(value: str) -> bool:
"""Check if the value looks like the start of an option."""
- return not value[0].isalnum() if value else False
+ if not value:
+ return False
+
+ c = value[0]
+ # Allow "/" since that starts a path.
+ return not c.isalnum() and c != "/"
def _is_incomplete_option(args: t.List[str], param: Parameter) -> bool:
diff --git a/tests/test_options.py b/tests/test_options.py
index 323d1c4..53179e8 100644
--- a/tests/test_options.py
+++ b/tests/test_options.py
@@ -4,6 +4,7 @@ import re
import pytest
import click
+from click import Option
def test_prefixes(runner):
@@ -727,6 +728,16 @@ def test_do_not_show_no_default(runner):
assert "[default: None]" not in message
+def test_do_not_show_default_empty_multiple():
+ """When show_default is True and multiple=True is set, it should not
+ print empty default value in --help output.
+ """
+ opt = click.Option(["-a"], multiple=True, help="values", show_default=True)
+ ctx = click.Context(click.Command("cli"))
+ message = opt.get_help_record(ctx)[1]
+ assert message == "values"
+
+
@pytest.mark.parametrize(
("args", "expect"),
[
@@ -763,3 +774,22 @@ def test_type_from_flag_value():
assert param.type is click.INT
param = click.Option(["-b", "x"], flag_value=8)
assert param.type is click.INT
+
+
+@pytest.mark.parametrize(
+ ("option", "expected"),
+ [
+ # Not boolean flags
+ pytest.param(Option(["-a"], type=int), False, id="int option"),
+ pytest.param(Option(["-a"], type=bool), False, id="bool non-flag [None]"),
+ pytest.param(Option(["-a"], default=True), False, id="bool non-flag [True]"),
+ pytest.param(Option(["-a"], default=False), False, id="bool non-flag [False]"),
+ pytest.param(Option(["-a"], flag_value=1), False, id="non-bool flag_value"),
+ # Boolean flags
+ pytest.param(Option(["-a"], is_flag=True), True, id="is_flag=True"),
+ pytest.param(Option(["-a/-A"]), True, id="secondary option [implicit flag]"),
+ pytest.param(Option(["-a"], flag_value=True), True, id="bool flag_value"),
+ ],
+)
+def test_is_bool_flag_is_correctly_set(option, expected):
+ assert option.is_bool_flag is expected
diff --git a/tests/test_shell_completion.py b/tests/test_shell_completion.py
index ac34ef9..46143c0 100644
--- a/tests/test_shell_completion.py
+++ b/tests/test_shell_completion.py
@@ -125,6 +125,14 @@ def test_path_types(type, expect):
assert c.type == expect
+def test_absolute_path():
+ cli = Command("cli", params=[Option(["-f"], type=Path())])
+ out = _get_completions(cli, ["-f"], "/ab")
+ assert len(out) == 1
+ c = out[0]
+ assert c.value == "/ab"
+
+
def test_option_flag():
cli = Command(
"cli",