Repository: pallets/click (python)

Issue:
Traceback when CLI option has bad default could be more helpful
### Expected Behavior

In the following command, I add an option `--multiple` with the metadata `multiple=True`, but the default `False` instead of `[False]`.

Ideally, the traceback should indicate that the `--multiple` option has a bad default.

```python
#!/usr/bin/env python
import click

@click.command()
@click.option("--multiple", multiple=True, default=False, show_default=True)
def cli(debug):
    pass

if __name__ == '__main__':
    cli()
```

### Actual Behavior

Tell us what happens instead.

```pytb
Traceback (most recent call last):
  File "./test_click.py", line 12, in <module>
    cli()
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 1025, in __call__
    return self.main(*args, **kwargs)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 954, in main
    with self.make_context(prog_name, args, **extra) as ctx:
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 852, in make_context
    self.parse_args(ctx, args)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 1261, in parse_args
    value, args = param.handle_parse_result(ctx, opts, args)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 2078, in handle_parse_result
    value, source = self.consume_value(ctx, opts)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 2509, in consume_value
    value, source = super().consume_value(ctx, opts)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 1975, in consume_value
    value = self.get_default(ctx)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 2453, in get_default
    return super().get_default(ctx, call=call)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 1957, in get_default
    return self.type_cast_value(ctx, value)
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 2007, in type_cast_value
    return _convert(value, (self.nargs != 1) + bool(self.multiple))
  File "/home/user/anaconda3/envs/pybids-pre/lib/python3.8/site-packages/click/core.py", line 2005, in _convert
    return tuple(_convert(x, level - 1) for x in value)
TypeError: 'bool' object is not iterable
```

I discovered this while running tests on pre-released dependencies, picking up click 8.0.0a1, which no longer accepts the above. The offending case was in a subcommand with many options, so it was not as obvious as it would be with a good error message.

### Environment

* Python version: 3.8
* Click version: 8.0.0a1


Pull request:
Better error message for bad parameter default
Added a `try` block to check whether the default value provided to an option with `multiple=True` is a valid iterable. If the value is not a valid iterable, a `TypeError` with a better error message is raised.

- fixes #1749 

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [x] 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 d3795e1..ac11bf3 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -182,6 +182,8 @@ Unreleased
     previous item. :issue:`1353`
 -   The ``Path`` param type can be passed ``path_type=pathlib.Path`` to
     return a path object instead of a string. :issue:`405`
+-   ``TypeError`` is raised when parameter with ``multiple=True`` or
+    ``nargs > 1`` has non-iterable default. :issue:`1749`
 
 
 Version 7.1.2
diff --git a/src/click/core.py b/src/click/core.py
index cc3aa14..f3192c5 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -2011,7 +2011,15 @@ class Parameter:
             if level == 0:
                 return self.type(value, self, ctx)
 
-            return tuple(_convert(x, level - 1) for x in value)
+            try:
+                iter_value = iter(value)
+            except TypeError:
+                raise TypeError(
+                    "Value for parameter with multiple = True or nargs > 1"
+                    " should be an iterable."
+                )
+
+            return tuple(_convert(x, level - 1) for x in iter_value)
 
         return _convert(value, (self.nargs != 1) + bool(self.multiple))
 


Test patch:
diff --git a/tests/test_options.py b/tests/test_options.py
index 128b860..65109d6 100644
--- a/tests/test_options.py
+++ b/tests/test_options.py
@@ -117,6 +117,20 @@ def test_multiple_required(runner):
     assert "Error: Missing option '-m' / '--message'." in result.output
 
 
+def test_multiple_bad_default(runner):
+    @click.command()
+    @click.option("--flags", multiple=True, default=False)
+    def cli(flags):
+        pass
+
+    result = runner.invoke(cli, [])
+    assert result.exception
+    assert (
+        "Value for parameter with multiple = True or nargs > 1 should be an iterable."
+        in result.exception.args
+    )
+
+
 def test_empty_envvar(runner):
     @click.command()
     @click.option("--mypath", type=click.Path(exists=True), envvar="MYPATH")