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
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Unreleased
``dict[str, Any]``.
- :class:`CompositeParamType` and the number-range base are now
generic with abstract methods.
- Split string values from ``default_map`` for parameters with ``nargs > 1``
or :class:`Tuple` type, matching environment variable behavior.
:issue:`2745` :pr:`3364`

Version 8.3.3
-------------
Expand Down
29 changes: 29 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,35 @@ And in action:
})
```

### Multi-value parameters

When a `default_map` value is a string for a parameter with `nargs > 1` or a
{class}`Tuple` type, the string is split automatically, the same way an
environment variable would be. By default, values are split on whitespace. See
[Multiple Options from Environment
Values](options.md#multiple-options-from-environment-values) for details on
splitting behavior.

```python
default_map = {
"draw": {
"point": "3 4", # split into ("3", "4") for nargs=2
"color": "red", # passed as-is for nargs=1
}
}
```

You can also pass an already-structured tuple or list, which will be used as-is
without splitting:

```python
default_map = {
"draw": {
"point": (3, 4), # used directly
}
}
```

## Context Defaults

```{versionadded} 2.0
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None),
}
myst_heading_anchors = 3

# HTML -----------------------------------------------------------------

Expand Down
5 changes: 5 additions & 0 deletions src/click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2356,6 +2356,11 @@ def consume_value(
value = default_map_value
source = ParameterSource.DEFAULT_MAP

# A string from default_map must be split for multi-value
# parameters, matching value_from_envvar behavior.
if isinstance(value, str) and self.nargs != 1:
value = self.type.split_envvar_value(value)

if value is UNSET:
default_value = self.get_default(ctx)
if default_value is not UNSET:
Expand Down
37 changes: 37 additions & 0 deletions tests/test_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,43 @@ def cli(value):
assert result.output == repr(expected)


@pytest.mark.parametrize(
("default_map", "option_kwargs", "cli_args", "expected"),
[
# String is split for nargs=2 option.
({"point": "3 4"}, {"nargs": 2, "type": int}, [], (3, 4)),
# String is split for explicit Tuple type.
({"point": "hello world"}, {"type": (str, str)}, [], ("hello", "world")),
# Already-structured tuple passes through unchanged.
({"point": ("a", "b")}, {"nargs": 2}, [], ("a", "b")),
# Already-structured list passes through unchanged.
({"point": [5, 6]}, {"nargs": 2, "type": int}, [], (5, 6)),
# CLI args override default_map for nargs > 1.
(
{"point": "3 4"},
{"nargs": 2, "type": int},
["--point", "10", "20"],
(10, 20),
),
],
)
def test_default_map_nargs(runner, default_map, option_kwargs, cli_args, expected):
"""A string in ``default_map`` for an option with ``nargs > 1`` should be
split the same way an environment variable string is split.

Regression test for https://github.com/pallets/click/issues/2745.
"""

@click.command()
@click.option("--point", **option_kwargs)
def cli(point):
click.echo(repr(point))

result = runner.invoke(cli, cli_args, default_map=default_map)
assert result.exit_code == 0
assert result.output.strip() == repr(expected)


def test_unset_in_default_map(runner):
"""An ``UNSET`` value in ``default_map`` should be treated as if
the key is absent, and so fallback to the parameter's own default.
Expand Down