Skip to content

Commit 10b77f9

Browse files
authored
Tone-down the case of default=True for flags in documentation (pallets#3049)
2 parents 0afce31 + a245613 commit 10b77f9

File tree

5 files changed

+33
-51
lines changed

5 files changed

+33
-51
lines changed

CHANGES.rst

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ Version 8.3.x
55

66
Unreleased
77

8-
- Rework relationship between ``flag_value`` and ``default``: the value given to
9-
``default`` is now left untouched, and keep the value it receive. So
10-
``default=<desired_value>`` is respected and ``<desired_value>`` is passed on as-is
11-
to the CLI function. With the exception of flag options, where setting
12-
``default=True`` maintain the legacy behavior of defaulting to the ``flag_value``.
13-
This allow ``default`` to be of any type, including ``bool`` or ``None``, fixing
14-
inconsistencies reported in: :issue:`1992` :issue:`2012` :issue:`2514`
15-
:issue:`2610` :issue:`3024` :pr:`3030`
8+
- **Improved flag option handling**: Reworked the relationship between ``flag_value``
9+
and ``default`` parameters for better consistency:
10+
11+
* The ``default`` parameter value is now preserved as-is and passed directly
12+
to CLI functions (no more unexpected transformations)
13+
* Exception: flag options with ``default=True`` maintain backward compatibility
14+
by defaulting to their ``flag_value``
15+
* The ``default`` parameter can now be any type (``bool``, ``None``, etc.)
16+
* Fixes inconsistencies reported in: :issue:`1992` :issue:`2514` :issue:`2610`
17+
:issue:`3024` :pr:`3030`
1618
- Allow ``default`` to be set on ``Argument`` for ``nargs = -1``. :issue:`2164`
1719
:pr:`3030`
1820
- Show correct auto complete value for ``nargs`` option in combination with flag

docs/options.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -335,14 +335,12 @@ To have an flag pass a value to the underlying function set `flag_value`. This a
335335
invoke(info)
336336
```
337337

338-
````{caution}
339-
The `default` argument of options always give to the underlying function its value *as-is*.
338+
````{note}
339+
The `default` value is given to the underlying function as-is. So if you set `default=None`, the value passed to the function is the `None` Python value. Same for any other type.
340340
341-
But for flags, the interaction between `flag_value` and `default` is a bit special.
341+
But there is a special case for flags. If a flag has a `flag_value`, then setting `default=True` is interpreted as *the flag should be activated by default*. So instead of the underlying function receiving the `True` Python value, it will receive the `flag_value`.
342342
343-
If a flag has a `flag_value`, setting `default` to `True` means that the flag is activated by default. Not that the value passed to the underlying function is the `True` Python value. Instead, the default value will be aligned to the `flag_value` behind the scenes.
344-
345-
Which means, the in example above, this option:
343+
Which means, in example above, this option:
346344
347345
```python
348346
@click.option('--upper', 'transformation', flag_value='upper', default=True)
@@ -354,9 +352,7 @@ is equivalent to:
354352
@click.option('--upper', 'transformation', flag_value='upper', default='upper')
355353
```
356354
357-
This was implemented to support legacy behavior, that will be removed in Click 9.0 to allow for default to take any value, including `True`.
358-
359-
In the mean time, to avoid confusion, it is recommended to always set `default` to the actual default value you want to pass to the underlying function, and not use `True`, `False` or `None`. Unless that's the precise value you want to explicitly force as default.
355+
Because the two are equivalent, it is recommended to always use the second form, and set `default` to the actual value you want to pass. And not use the special `True` case. This makes the code more explicit and predictable.
360356
````
361357

362358
## Values from Environment Variables

src/click/core.py

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,15 +2606,6 @@ class Option(Parameter):
26062606
:param hidden: hide this option from help outputs.
26072607
:param attrs: Other command arguments described in :class:`Parameter`.
26082608
2609-
.. caution::
2610-
Flags specifying a ``flag_value`` and whose ``default=True`` will have
2611-
their ``default`` aligned to the ``flag_value``.
2612-
2613-
This means there is no way to setup a flag whose default ``True`` and
2614-
whose ``flag_value`` is something else than ``True``.
2615-
2616-
This is to support legacy behavior that will be removed in Click 9.0.
2617-
26182609
.. versionchanged:: 8.2
26192610
``envvar`` used with ``flag_value`` will always use the ``flag_value``,
26202611
previously it would use the value of the environment variable.
@@ -2742,23 +2733,13 @@ def __init__(
27422733
if self.default is UNSET and not self.required:
27432734
self.default = False
27442735

2745-
# XXX Support the legacy case of aligning the default value with the flag_value
2746-
# for flags whose default is explicitly set to True. As long as we have this
2747-
# condition, there is no way a flag can have a default set to True, unless its
2748-
# flag_value itself is set to True. Refs:
2736+
# Support the special case of aligning the default value with the flag_value
2737+
# for flags whose default is explicitly set to True. Note that as long as we
2738+
# have this condition, there is no way a flag can have a default set to True,
2739+
# and a flag_value set to something else. Refs:
27492740
# https://github.com/pallets/click/issues/3024#issuecomment-3146199461
2750-
# https://github.com/pallets/click/pull/3030/files#r2288936493
2741+
# https://github.com/pallets/click/pull/3030/commits/06847da
27512742
if self.default is True and self.flag_value is not UNSET:
2752-
# This message is a convoluted way to explain that if you want things
2753-
# to be equal, make them equal.
2754-
# warnings.warn(
2755-
# "A flag's `default` value will no longer be aligned with its "
2756-
# "`flag_value` if `default=True` in Click 9.0. If you want the flag "
2757-
# "to get the same `default` as its `flag_value`, update the option "
2758-
# "to make its `default` parameter equal to its `flag_value`.",
2759-
# DeprecationWarning,
2760-
# stacklevel=2,
2761-
# )
27622743
self.default = self.flag_value
27632744

27642745
# Set the default flag_value if it is not set.
@@ -3070,11 +3051,14 @@ def prompt_for_value(self, ctx: Context) -> t.Any:
30703051
# one.
30713052
if default in (UNSET, None):
30723053
default = None
3073-
# Nothing prevent you to declare an option that is auto-detected as a
3074-
# boolean flag, is allow to prompt but still declare a non-boolean default.
3075-
# So with this casting, we aligns the default value to the prompt behavior.
3076-
# The prompt is going to default to [Y/n]), and so not entering a value for
3077-
# input is expected to make the option takes True as the default.
3054+
# Nothing prevent you to declare an option that is simultaneously:
3055+
# 1) auto-detected as a boolean flag,
3056+
# 2) allowed to prompt, and
3057+
# 3) still declare a non-boolean default.
3058+
# This forced casting into a boolean is necessary to align any non-boolean
3059+
# default to the prompt, which is going to be a [y/n]-style confirmation
3060+
# because the option is still a boolean flag. That way, instead of [y/n],
3061+
# we get [Y/n] or [y/N] depending on the truthy value of the default.
30783062
# Refs: https://github.com/pallets/click/pull/3030#discussion_r2289180249
30793063
else:
30803064
default = bool(default)

tests/test_basic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,8 @@ def cli(flag):
302302
(None, [], None),
303303
# Default is normalized to None if it is UNSET.
304304
(UNSET, [], None),
305-
# Legacy case: if default=True and flag_value is set, The value returned is the
306-
# flag_value, not default itself.
305+
# Special case: if default=True and flag_value is set, the value returned is the
306+
# flag_value, not the True Python value itself.
307307
(True, [], "upper"),
308308
# Non-string defaults are process as strings by the default Parameter's type.
309309
(False, [], "False"),

tests/test_options.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,11 +1478,11 @@ def cmd(foo):
14781478
("xMl", [], "xMl"),
14791479
(" ᕕ( ᐛ )ᕗ ", [], " ᕕ( ᐛ )ᕗ "),
14801480
(None, [], None),
1481-
# Legacy case: UNSET is not exposed directly to the callback, but converted to
1481+
# Special case: UNSET is not provided as-is to the callback, but normalized to
14821482
# None.
14831483
(UNSET, [], None),
1484-
# Legacy case: if default=True and flag_value is set, The value returned is the
1485-
# flag_value, not default itself.
1484+
# Special case: if default=True and flag_value is set, the value returned is the
1485+
# flag_value, not the True Python value itself.
14861486
(True, [], "js"),
14871487
# Non-string defaults are process as strings by the default Parameter's type.
14881488
(False, [], "False"),

0 commit comments

Comments
 (0)