diff --git a/CHANGELOG.md b/CHANGELOG.md index eefbaad..92ff8e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ s. - feat: User defined parsers can access the `TypeView` by accepting it as an argument. - feat: Add new API for defining subcommands as methods. - feat: Add Arg.show_default option to optionally avoid displaying default in help text. +- fix: Only show_default on `--*/--no-*` pair bool arguments for the actual default. ## 0.23 diff --git a/src/cappa/arg.py b/src/cappa/arg.py index 53e0391..89ec557 100644 --- a/src/cappa/arg.py +++ b/src/cappa/arg.py @@ -621,11 +621,18 @@ def explode_negated_bool_args(args: typing.Sequence[Arg]) -> typing.Iterable[Arg positives = [item for item in long if "--no-" not in item] if negatives and positives: positive_arg = dataclasses.replace( - arg, long=positives, action=ArgAction.store_true + arg, + long=positives, + action=ArgAction.store_true, + show_default=arg.default is True, ) negative_arg = dataclasses.replace( - arg, long=negatives, action=ArgAction.store_false + arg, + long=negatives, + action=ArgAction.store_false, + show_default=arg.default is False, ) + yield positive_arg yield negative_arg yielded = True diff --git a/tests/arg/test_show_default.py b/tests/arg/test_show_default.py new file mode 100644 index 0000000..0f90e69 --- /dev/null +++ b/tests/arg/test_show_default.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from dataclasses import dataclass + +import pytest +from typing_extensions import Annotated + +import cappa +from tests.utils import TestOutput, backends, parse + + +@backends +def test_show_default_default_true(backend, capsys): + @dataclass + class Command: + foo: bool = False + + assert parse(Command, backend=backend).foo is False + + with pytest.raises(cappa.HelpExit): + parse(Command, "--help", backend=backend) + + output = TestOutput.from_capsys(capsys) + assert "(Default: False)" in output.stdout + + +@backends +def test_show_default_set_false(backend, capsys): + @dataclass + class Command: + foo: Annotated[bool, cappa.Arg(show_default=False)] = False + + assert parse(Command, backend=backend).foo is False + + with pytest.raises(cappa.HelpExit): + parse(Command, "--help", backend=backend) + + output = TestOutput.from_capsys(capsys) + assert "(Default: False)" not in output.stdout + + +@backends +def test_show_default_no_option_shows_for_false_default(backend, capsys): + @dataclass + class Command: + foo: Annotated[bool, cappa.Arg(long="--foo/--no-foo")] = False + + assert parse(Command, backend=backend).foo is False + + with pytest.raises(cappa.HelpExit): + parse(Command, "--help", backend=backend) + + stdout = TestOutput.from_capsys(capsys).stdout.replace(" ", "") + assert "[--foo](Default:True)" not in stdout + assert "[--no-foo](Default:False)" in stdout + + +@backends +def test_show_default_no_option_shows_for_true_default(backend, capsys): + @dataclass + class Command: + foo: Annotated[bool, cappa.Arg(long="--foo/--no-foo")] = True + + assert parse(Command, backend=backend).foo is True + + with pytest.raises(cappa.HelpExit): + parse(Command, "--help", backend=backend) + + stdout = TestOutput.from_capsys(capsys).stdout.replace(" ", "") + assert "[--foo](Default:True)" in stdout + assert "[--no-foo](Default:False)" not in stdout diff --git a/tests/utils.py b/tests/utils.py index 0e1446b..04fcf97 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,4 +1,5 @@ import contextlib +from dataclasses import dataclass from typing import Union from unittest.mock import patch @@ -57,3 +58,17 @@ def ignore_docstring_parser(monkeypatch): def strip_trailing_whitespace(text): return "\n".join([line.rstrip() for line in text.split("\n")]) + + +@dataclass +class TestOutput: + stdout: str + stderr: str + + @classmethod + def from_capsys(cls, capsys): + outerr = capsys.readouterr() + + out = strip_trailing_whitespace(outerr.out) + err = strip_trailing_whitespace(outerr.err) + return cls(out, err)