Skip to content

Commit a317fb2

Browse files
committed
Fixes flag default handling for boolean options
Ensures boolean flag options correctly determine their default values when not explicitly set. Adds tests to validate proper behavior for various flag configurations, improving reliability. Fixes #2897
1 parent af73ce4 commit a317fb2

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Version 8.2.1
44
-------------
55

6+
- Fixes flag default handling for boolean options. :issue:`2897` :pr:`2908`
67

78
Version 8.2.0
89
-------------

src/click/core.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,6 +2618,12 @@ def __init__(
26182618
# default.
26192619
self.type = types.convert_type(None, flag_value)
26202620

2621+
if is_flag and isinstance(self.type, types.BoolParamType):
2622+
# If the type is a boolean, we need to set the flag_value
2623+
# to True or False depending on the default.
2624+
if flag_value is None:
2625+
flag_value = not self.default
2626+
26212627
self.is_flag: bool = is_flag
26222628
self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType)
26232629
self.flag_value: t.Any = flag_value

tests/test_defaults.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,43 @@ def foo(name):
8484

8585
result = runner.invoke(cli, ["foo", "--help"], default_map={"foo": {"name": True}})
8686
assert "default: name" in result.output
87+
88+
89+
def test_flag_default_bool(runner):
90+
"""test flag with default bool"""
91+
92+
@click.command()
93+
@click.option("--foo", is_flag=True, default=False, type=click.BOOL)
94+
@click.option("--bar", is_flag=True, default=False, type=bool)
95+
@click.option("--baz", is_flag=True, default=True, type=click.BOOL)
96+
@click.option("--qux", is_flag=True, default=True, type=bool)
97+
def cli(foo, bar, baz, qux):
98+
assert isinstance(foo, bool)
99+
assert isinstance(bar, bool)
100+
assert isinstance(baz, bool)
101+
assert isinstance(qux, bool)
102+
click.echo(f"foo: {foo}, bar: {bar}, baz: {baz}, qux: {qux}")
103+
104+
result = runner.invoke(cli, [])
105+
assert not result.exception
106+
assert "foo: False, bar: False, baz: True, qux: True" in result.output
107+
108+
result = runner.invoke(cli, ["--foo"])
109+
assert not result.exception
110+
assert "foo: True, bar: False, baz: True, qux: True" in result.output
111+
112+
result = runner.invoke(cli, ["--bar"])
113+
assert not result.exception
114+
assert "foo: False, bar: True, baz: True, qux: True" in result.output
115+
116+
result = runner.invoke(cli, ["--baz"])
117+
assert not result.exception
118+
assert "foo: False, bar: False, baz: False, qux: True" in result.output
119+
120+
result = runner.invoke(cli, ["--qux"])
121+
assert not result.exception
122+
assert "foo: False, bar: False, baz: True, qux: False" in result.output
123+
124+
result = runner.invoke(cli, ["--foo", "--bar", "--baz", "--qux"])
125+
assert not result.exception
126+
assert "foo: True, bar: True, baz: False, qux: False" in result.output

0 commit comments

Comments
 (0)