Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b64ea07
Differentiate absence of value and value of absence for `default` and…
kdeldycke Aug 6, 2025
8645e70
Do not simple-tick Python literal values
kdeldycke Aug 21, 2025
9be1039
Keep original inconsistent ticks to reduce noise
kdeldycke Aug 21, 2025
40fb375
Keep original inconsistent ticks to reduce noise
kdeldycke Aug 21, 2025
c442c05
Rewrap text
kdeldycke Aug 21, 2025
634549f
Don't refactor variable names unnecessarily
kdeldycke Aug 21, 2025
44c2bea
Do not change the original structure of the code
kdeldycke Aug 21, 2025
cf0e524
Keep the change entry concise
kdeldycke Aug 21, 2025
60feda3
Do not mention UNSET
kdeldycke Aug 21, 2025
b39590f
Make the source selection logic clearer
kdeldycke Aug 21, 2025
f561f18
Do not mention UNSET and keep the change entry small
kdeldycke Aug 21, 2025
2d1ceff
Rework method documentation
kdeldycke Aug 21, 2025
2fbc8b1
Reduce unnecessary changes
kdeldycke Aug 21, 2025
8386598
Typo
kdeldycke Aug 21, 2025
11bfb2c
Remove assertion already covered by the type annotation
kdeldycke Aug 21, 2025
c498ced
Add comments about the test cases
kdeldycke Aug 21, 2025
f9ec2ea
Check falsy sentinels
kdeldycke Aug 21, 2025
6417ace
Typo
kdeldycke Aug 21, 2025
b035019
Add some discussion context
kdeldycke Aug 21, 2025
354788e
Comment the test cases
kdeldycke Aug 21, 2025
7b84990
Describe the progression of tests
kdeldycke Aug 21, 2025
472bf38
Describe test
kdeldycke Aug 21, 2025
e9e5002
Do not mention UNSET
kdeldycke Aug 21, 2025
9f7d991
Add description
kdeldycke Aug 21, 2025
0acca45
Mark recently documented methods as private
kdeldycke Aug 23, 2025
bbe1eb6
Remove duplicate test
kdeldycke Aug 23, 2025
06847da
Support legacy case of default aligning to flag_value for flag whose …
kdeldycke Aug 23, 2025
7f4fa21
Lint
kdeldycke Aug 23, 2025
cd66233
Remove bad ref
kdeldycke Aug 23, 2025
4f70b37
Fix typing
kdeldycke Aug 23, 2025
abaef53
Typing
kdeldycke Aug 23, 2025
bb2a1d9
Better doc and tests for multiple
kdeldycke Aug 23, 2025
96e4c75
Add explanation for the casting
kdeldycke Aug 23, 2025
a2b699a
Fix import
kdeldycke Aug 23, 2025
029bbed
Hide UNSET in the callback
kdeldycke Aug 23, 2025
b9abeaa
Hint at the concepts carried by default
kdeldycke Aug 23, 2025
285f45c
Lint
kdeldycke Aug 23, 2025
dc8e539
Merge branch 'main' into fix-flag-none-value
Rowlando13 Aug 24, 2025
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
19 changes: 15 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
.. currentmodule:: click

Version 8.2.x
Version 8.3.x
-------------

Unreleased

- Rework relationship between ``flag_value`` and ``default``: the value given to
``default`` is now left untouched, and keep the value it receive. So
``default=<desired_value>`` is respected and ``<desired_value>`` is passed on as-is
to the CLI function. With the exception of flag options, where setting
``default=True`` maintain the legacy behavior of defaulting to the ``flag_value``.
This allow ``default`` to be of any type, including ``bool`` or ``None``, fixing
inconsistencies reported in: :issue:`1992` :issue:`2012` :issue:`2514`
:issue:`2610` :issue:`3024` :pr:`3030`
- Allow ``default`` to be set on ``Argument`` for ``nargs = -1``. :issue:`2164`
:pr:`3030`
- Show correct auto complete value for ``nargs`` option in combination with flag
option :issue:`2813`
- Show correct auto complete value for nargs option in combination with flag option :issue:`2813`
- Fix handling of quoted and escaped parameters in Fish autocompletion. :issue:`2995` :pr:`3013`
- Lazily import ``shutil``. :pr:`3023`
Expand All @@ -14,12 +25,12 @@ Version 8.2.2

Released 2025-07-31

- Fix reconciliation of `default`, `flag_value` and `type` parameters for
- Fix reconciliation of ``default``, ``flag_value`` and ``type`` parameters for
flag options, as well as parsing and normalization of environment variables.
:issue:`2952` :pr:`2956`
- Fix typing issue in ``BadParameter`` and ``MissingParameter`` exceptions for the
parameter ``param_hint`` that did not allow for a sequence of string where the
underlying functino ``_join_param_hints`` allows for it. :issue:`2777` :pr:`2990`
underlying function ``_join_param_hints`` allows for it. :issue:`2777` :pr:`2990`
- Use the value of ``Enum`` choices to render their default value in help
screen. Refs :issue:`2911` :pr:`3004`
- Fix completion for the Z shell (``zsh``) for completion items containing
Expand Down
33 changes: 29 additions & 4 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ If you want to define an alias for the second option only, then you will need to

## Flag Value

To have an flag pass a value to the underlying function set `flag_value`. This automatically sets `is_flag=True`. To set a default flag, set `default=True`. Setting flag values can be used to create patterns like this:
To have an flag pass a value to the underlying function set `flag_value`. This automatically sets `is_flag=True`. To mark the flag as default, set `default=True`. Setting flag values can be used to create patterns like this:

```{eval-rst}
.. click:example::
Expand All @@ -335,6 +335,30 @@ To have an flag pass a value to the underlying function set `flag_value`. This a
invoke(info)
```

````{caution}
The `default` argument of options always give to the underlying function its value *as-is*.

But for flags, the interaction between `flag_value` and `default` is a bit special.

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.

Which means, the in example above, this option:

```python
@click.option('--upper', 'transformation', flag_value='upper', default=True)
```

is equivalent to:

```python
@click.option('--upper', 'transformation', flag_value='upper', default='upper')
```

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`.

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.
````

## Values from Environment Variables

To pass in a value in from a specific environment variable use `envvar`.
Expand Down Expand Up @@ -386,10 +410,11 @@ Here are the rules used to parse environment variable values for flag options:
- If the flag option has a `flag_value` argument, passing that value in the environment variable will activate the flag, in addition to all the cases described above
- Any other value is interpreted as deactivating the flag

.. caution::
For boolean flags with a pair of values, the only recognized environment variable is the one provided to the `envvar` argument.
```{caution}
For boolean flags with a pair of values, the only recognized environment variable is the one provided to the `envvar` argument.

So an option defined as `--flag\--no-flag`, with a `envvar="FLAG"` parameter, there is no magical `NO_FLAG=<anything>` variable that is recognized. Only the `FLAG=<anything>` environment variable is recognized.
So an option defined as `--flag\--no-flag`, with a `envvar="FLAG"` parameter, there is no magical `NO_FLAG=<anything>` variable that is recognized. Only the `FLAG=<anything>` environment variable is recognized.
```

Once the status of the flag has been determine to be activated or not, the `flag_value` is used as the value of the flag if it is activated. If the flag is not activated, the value of the flag is set to `None` by default.

Expand Down
25 changes: 25 additions & 0 deletions src/click/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from __future__ import annotations

import enum
import typing as t


class Sentinel(enum.Enum):
"""Enum used to define sentinel values.

.. seealso::

`PEP 661 - Sentinel Values <https://peps.python.org/pep-0661/>`_.
"""

UNSET = object()

def __repr__(self) -> str:
return f"{self.__class__.__name__}.{self.name}"


UNSET = Sentinel.UNSET
"""A sentinel object used to indicate that a value is not set."""

T_UNSET = t.Literal[UNSET] # type: ignore[valid-type]
"""Type hint for the :data:`UNSET` sentinel value."""
Loading
Loading