Skip to content

Commit 63ee5ec

Browse files
committed
Split string values from default_map for multi-value parameters
Fixes #2745
1 parent f1f191e commit 63ee5ec

3 files changed

Lines changed: 45 additions & 0 deletions

File tree

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ Unreleased
4040
- Change :class:`ParameterSource` to an :class:`~enum.IntEnum` and reorder
4141
its members from most to least explicit, so values can be compared to
4242
check whether a parameter was explicitly provided. :issue:`2879` :pr:`3248`
43+
- Split string values from ``default_map`` for parameters with ``nargs > 1``
44+
or :class:`Tuple` type, matching environment variable behavior.
45+
:issue:`2745` :pr:`3364`
4346

4447
Version 8.3.2
4548
-------------

src/click/core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,6 +2356,11 @@ def consume_value(
23562356
value = default_map_value
23572357
source = ParameterSource.DEFAULT_MAP
23582358

2359+
# A string from default_map must be split for multi-value
2360+
# parameters, matching value_from_envvar behavior.
2361+
if isinstance(value, str) and self.nargs != 1:
2362+
value = self.type.split_envvar_value(value)
2363+
23592364
if value is UNSET:
23602365
default_value = self.get_default(ctx)
23612366
if default_value is not UNSET:

tests/test_defaults.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,43 @@ def cli(value):
357357
assert result.output == repr(expected)
358358

359359

360+
@pytest.mark.parametrize(
361+
("default_map", "option_kwargs", "cli_args", "expected"),
362+
[
363+
# String is split for nargs=2 option.
364+
({"point": "3 4"}, {"nargs": 2, "type": int}, [], (3, 4)),
365+
# String is split for explicit Tuple type.
366+
({"point": "hello world"}, {"type": (str, str)}, [], ("hello", "world")),
367+
# Already-structured tuple passes through unchanged.
368+
({"point": ("a", "b")}, {"nargs": 2}, [], ("a", "b")),
369+
# Already-structured list passes through unchanged.
370+
({"point": [5, 6]}, {"nargs": 2, "type": int}, [], (5, 6)),
371+
# CLI args override default_map for nargs > 1.
372+
(
373+
{"point": "3 4"},
374+
{"nargs": 2, "type": int},
375+
["--point", "10", "20"],
376+
(10, 20),
377+
),
378+
],
379+
)
380+
def test_default_map_nargs(runner, default_map, option_kwargs, cli_args, expected):
381+
"""A string in ``default_map`` for an option with ``nargs > 1`` should be
382+
split the same way an environment variable string is split.
383+
384+
Regression test for https://github.com/pallets/click/issues/2745.
385+
"""
386+
387+
@click.command()
388+
@click.option("--point", **option_kwargs)
389+
def cli(point):
390+
click.echo(repr(point))
391+
392+
result = runner.invoke(cli, cli_args, default_map=default_map)
393+
assert result.exit_code == 0
394+
assert result.output.strip() == repr(expected)
395+
396+
360397
def test_unset_in_default_map(runner):
361398
"""An ``UNSET`` value in ``default_map`` should be treated as if
362399
the key is absent, and so fallback to the parameter's own default.

0 commit comments

Comments
 (0)