Repository: pallets/click (python)

Issue:
Custom default label ignored if default is None
I found out that custom default label is not shown when `default` is `None`. In some cases `default = None` is intentional, but custom default label would be still helpful.

An example with `--limit` option, with `None` as `default` meaning no limit:
```python
import click

@click.command()
@click.option('--limit', type=int, show_default='unlimited')
def main(limit: int):
    print('Limit: {}'.format(limit))

if __name__ == '__main__':
    main()
```

### Expected Behavior
Tell us what should happen.

```sh
$ python3 /tmp/foo.py --help
Usage: foo.py [OPTIONS]

Options:
  --limit INTEGER  [default: unlimited]
  --help           Show this message and exit.
```

### Actual Behavior
Tell us what happens instead.

```sh
$ python3 /tmp/foo.py --help
Usage: foo.py [OPTIONS]

Options:
  --limit INTEGER
  --help           Show this message and exit.
```
Default is not shown, making the description less useful.

### Environment

* Python version: 3.9.1
* Click version: 7.1.2

Pull request:
show_defaults now accepts string value as suggested by the docs
Fixes #1732 by removing the mandatory "default" flag for using show_defaults with a string value.

- Fixes #1732 

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [docs already up2date] Add or update relevant docs, in the docs folder and in code. 
- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [x] Add `.. versionchanged::` entries in any relevant code docs.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 343c817..ea2b00b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -157,6 +157,8 @@ Unreleased
     ``Choice`` :issue:`1692`
 -   Use ``mkstemp()`` instead of ``mktemp()`` in pager implementation.
     :issue:`1752`
+-   If ``Option.show_default`` is a string, it is displayed even if
+    ``default`` is ``None``. :issue:`1732`
 
 
 Version 7.1.2
diff --git a/src/click/core.py b/src/click/core.py
index 227025d..d04becb 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -2405,9 +2405,12 @@ class Option(Parameter):
                 extra.append(f"env var: {var_str}")
 
         default_value = self.get_default(ctx, call=False)
+        show_default_is_str = isinstance(self.show_default, str)
 
-        if default_value is not None and (self.show_default or ctx.show_default):
-            if isinstance(self.show_default, str):
+        if show_default_is_str or (
+            default_value is not None and (self.show_default or ctx.show_default)
+        ):
+            if show_default_is_str:
                 default_string = f"({self.show_default})"
             elif isinstance(default_value, (list, tuple)):
                 default_string = ", ".join(str(d) for d in default_value)


Test patch:
diff --git a/tests/test_options.py b/tests/test_options.py
index 2c04941..e9801b1 100644
--- a/tests/test_options.py
+++ b/tests/test_options.py
@@ -660,6 +660,14 @@ def test_show_default_boolean_flag_value(runner):
     assert "[default: False]" in message
 
 
+def test_show_default_string(runner):
+    """When show_default is a string show that value as default."""
+    opt = click.Option(["--limit"], show_default="unlimited")
+    ctx = click.Context(click.Command("cli"))
+    message = opt.get_help_record(ctx)[1]
+    assert "[default: (unlimited)]" in message
+
+
 @pytest.mark.parametrize(
     ("args", "expect"),
     [