Repository: pallets/click (python)

Issue:
`flag_value` is not taken into account with `envvar`
When using the ~~--debug option~~ `DEBUG` environment variable in the sample command, the debug value is not correctly set (`flag_value`). It is expected to be either `logging.DEBUG` or `None`, but it seems to be getting the integer value directly from the environment variable.

Sample:

```python
import logging
import os
import sys

import click


# Works as expected
# sys.argv = ['', '--debug']

# Does not work as expected
# os.environ['DEBUG'] = '1'

@click.command()
@click.option('--debug', is_flag=True, flag_value=logging.DEBUG, envvar='DEBUG')
def sample(debug):
    click.echo(f"DEBUG: {debug}")
    assert debug in [logging.DEBUG, None], f"Invalid debug value: {debug} - expected >{logging.DEBUG}< or None"


if __name__ == '__main__':
    sample()

```

There is no different in using `os.environ` or  `DEBUG=1 python cli.py`.

`DEBUG=8 python cli.py` prints out: `8`

Environment:

- Python version: 3.12.4
- Click version: 8.1.7


Pull request:
Added functionality to set flag_value correctly when using envvar
```python
@click.option('--upper', flag_value='upper', envvar='UPPER')
def cmd(upper):
    click.echo(upper)
    return upper
```

### Default use
The expectation of the above code when running `python cmd.py --upper` is to print to stdout `upper` (the flag value). This is default behaviour and works correctly.

### Environment variable use
What is the expectation when we run `UPPER=32 python cmd.py` ?

The program should still print to the screen `upper`, because that is the `flag_value` and there exists an env variable defined with the name `UPPER`, yet it actually prints `32`, the value of the environment variable, which i don't believe is intended.

*I also added a test for this functionality called `test_envvar_flag_value`*
fixes #2746 


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 7bb0762..495eb2a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -51,6 +51,9 @@ Unreleased
 -   Add ``ProgressBar(hidden: bool)`` to allow hiding the progressbar. :issue:`2609`
 -   A ``UserWarning`` will be shown when multiple parameters attempt to use the
     same name. :issue:`2396``
+-   When using ``Option.envvar`` with ``Option.flag_value``, the ``flag_value``
+    will always be used instead of the value of the environment variable.
+    :issue:`2746` :pr:`2788`
 
 
 Version 8.1.8
diff --git a/src/click/core.py b/src/click/core.py
index 5420c4b..0b924ca 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -2430,15 +2430,19 @@ class Option(Parameter):
     :param hidden: hide this option from help outputs.
     :param attrs: Other command arguments described in :class:`Parameter`.
 
-    .. versionchanged:: 8.1.0
+    .. versionchanged:: 8.2
+        ``envvar`` used with ``flag_value`` will always use the ``flag_value``,
+        previously it would use the value of the environment variable.
+
+    .. versionchanged:: 8.1
         Help text indentation is cleaned here instead of only in the
         ``@option`` decorator.
 
-    .. versionchanged:: 8.1.0
+    .. versionchanged:: 8.1
         The ``show_default`` parameter overrides
         ``Context.show_default``.
 
-    .. versionchanged:: 8.1.0
+    .. versionchanged:: 8.1
         The default of a single option boolean flag is not shown if the
         default value is ``False``.
 
@@ -2864,6 +2868,8 @@ class Option(Parameter):
         rv = super().resolve_envvar_value(ctx)
 
         if rv is not None:
+            if self.is_flag and self.flag_value:
+                return str(self.flag_value)
             return rv
 
         if (


Test patch:
diff --git a/tests/test_arguments.py b/tests/test_arguments.py
index 825bcc4..5dc56a4 100644
--- a/tests/test_arguments.py
+++ b/tests/test_arguments.py
@@ -198,6 +198,19 @@ def test_nargs_envvar(runner, nargs, value, expect):
         assert result.return_value == expect
 
 
+def test_envvar_flag_value(runner):
+    @click.command()
+    # is_flag is implicitly true
+    @click.option("--upper", flag_value="upper", envvar="UPPER")
+    def cmd(upper):
+        click.echo(upper)
+        return upper
+
+    # For whatever value of the `env` variable, if it exists, the flag should be `upper`
+    result = runner.invoke(cmd, env={"UPPER": "whatever"})
+    assert result.output.strip() == "upper"
+
+
 def test_nargs_envvar_only_if_values_empty(runner):
     @click.command()
     @click.argument("arg", envvar="X", nargs=-1)