Repository: pallets/click

Issue:
show_default and default_map don't play nice together
```python
#!/usr/bin/env python
import click

@click.command(context_settings={
    "show_default": True, "default_map": {"a": "b"}
})
@click.option("-a", default="c")
def func(a):
    print(a)

if __name__ == "__main__":
    func()
```
```console
$ # This is expected
$ ./cli.py
b
$ # This is not (default should be b)
$ ./cli.py --help
Usage: cli.py [OPTIONS]

Options:
  -a TEXT  [default: c]
  --help   Show this message and exit.  [default: False]
```

### Expected Behavior

I expect the default shown to be identical to the one being used.

### Actual Behavior

The default shown was the value provided as `default`, without taking the `default_map` into account

### Environment

* Python version: 3.7
* Click version: ``click==7.1.2``



Discussion:
I may be able to make a failing test or a PR if you point me to the right direction. Would calling `lookup_default` instead of `.default` in this line be enough ?

https://github.com/pallets/click/blob/bce4ea4ba54e15959cb412d6793634e0c9b24491/src/click/core.py#L1936
Seems plausible, happy to review a PR.
Ok, I'll try to remember to communicate here whether it happens or not. If I have neither said nor committed anything by May 17th, assume I have forgotten about it and you're free to go :)

Resolving patch:
diff --git a/src/click/core.py b/src/click/core.py
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -1,6 +1,5 @@
 import enum
 import errno
-import inspect
 import os
 import sys
 from contextlib import contextmanager
@@ -613,15 +612,23 @@ def ensure_object(self, object_type):
             self.obj = rv = object_type()
         return rv
 
-    def lookup_default(self, name):
-        """Looks up the default for a parameter name.  This by default
-        looks into the :attr:`default_map` if available.
+    def lookup_default(self, name, call=True):
+        """Get the default for a parameter from :attr:`default_map`.
+
+        :param name: Name of the parameter.
+        :param call: If the default is a callable, call it. Disable to
+            return the callable instead.
+
+        .. versionchanged:: 8.0
+            Added the ``call`` parameter.
         """
         if self.default_map is not None:
-            rv = self.default_map.get(name)
-            if callable(rv):
-                rv = rv()
-            return rv
+            value = self.default_map.get(name)
+
+            if call and callable(value):
+                return value()
+
+            return value
 
     def fail(self, message):
         """Aborts the execution of the program with a specific error
@@ -1920,14 +1927,33 @@ def make_metavar(self):
             metavar += "..."
         return metavar
 
-    def get_default(self, ctx):
-        """Given a context variable this calculates the default value."""
-        # Otherwise go with the regular default.
-        if callable(self.default):
-            rv = self.default()
-        else:
-            rv = self.default
-        return self.type_cast_value(ctx, rv)
+    def get_default(self, ctx, call=True):
+        """Get the default for the parameter. Tries
+        :meth:`Context.lookup_value` first, then the local default.
+
+        :param ctx: Current context.
+        :param call: If the default is a callable, call it. Disable to
+            return the callable instead.
+
+        .. versionchanged:: 8.0
+            Looks at ``ctx.default_map`` first.
+
+        .. versionchanged:: 8.0
+            Added the ``call`` parameter.
+        """
+        value = ctx.lookup_default(self.name, call=False)
+
+        if value is None:
+            value = self.default
+
+        if callable(value):
+            if not call:
+                # Don't type cast the callable.
+                return value
+
+            value = value()
+
+        return self.type_cast_value(ctx, value)
 
     def add_to_parser(self, parser, ctx):
         pass
@@ -2355,12 +2381,15 @@ def _write_opts(opts):
                     else envvar
                 )
                 extra.append(f"env var: {var_str}")
-        if self.default is not None and (self.show_default or ctx.show_default):
+
+        default_value = self.get_default(ctx, call=False)
+
+        if default_value is not None and (self.show_default or ctx.show_default):
             if isinstance(self.show_default, str):
                 default_string = f"({self.show_default})"
-            elif isinstance(self.default, (list, tuple)):
-                default_string = ", ".join(str(d) for d in self.default)
-            elif inspect.isfunction(self.default):
+            elif isinstance(default_value, (list, tuple)):
+                default_string = ", ".join(str(d) for d in default_value)
+            elif callable(default_value):
                 default_string = "(dynamic)"
             elif self.is_bool_flag and self.secondary_opts:
                 # For boolean flags that have distinct True/False opts,
@@ -2369,7 +2398,8 @@ def _write_opts(opts):
                     (self.opts if self.default else self.secondary_opts)[0]
                 )[1]
             else:
-                default_string = self.default
+                default_string = default_value
+
             extra.append(f"default: {default_string}")
 
         if isinstance(self.type, _NumberRangeBase):
@@ -2386,7 +2416,7 @@ def _write_opts(opts):
 
         return ("; " if any_prefix_is_slash else " / ").join(rv), help
 
-    def get_default(self, ctx):
+    def get_default(self, ctx, call=True):
         # If we're a non boolean flag our default is more complex because
         # we need to look at all flags in the same group to figure out
         # if we're the the default one in which case we return the flag
@@ -2395,9 +2425,10 @@ def get_default(self, ctx):
             for param in ctx.command.params:
                 if param.name == self.name and param.default:
                     return param.flag_value
+
             return None
 
-        return super().get_default(ctx)
+        return super().get_default(ctx, call=call)
 
     def prompt_for_value(self, ctx):
         """This is an alternative flow that can be activated in the full


Test patch:
diff --git a/tests/test_options.py b/tests/test_options.py
--- a/tests/test_options.py
+++ b/tests/test_options.py
@@ -188,6 +188,18 @@ def cmd(arg, arg2):
     assert "1, 2" in result.output
 
 
+def test_show_default_default_map(runner):
+    @click.command()
+    @click.option("--arg", default="a", show_default=True)
+    def cmd(arg):
+        click.echo(arg)
+
+    result = runner.invoke(cmd, ["--help"], default_map={"arg": "b"})
+
+    assert not result.exception
+    assert "[default: b]" in result.output
+
+
 def test_multiple_default_type():
     opt = click.Option(["-a"], multiple=True, default=(1, 2))
     assert opt.nargs == 1