From 0ff8ccb98039495475f37816ede34f86f74eb095 Mon Sep 17 00:00:00 2001 From: pooyanazad Date: Tue, 30 Jun 2026 20:17:32 +0200 Subject: [PATCH 1/2] fix: hide INTEGER from help for count=True options (closes #1869) --- tests/test_core.py | 28 ++++++++++++++++++++++++++++ typer/core.py | 2 ++ typer/rich_utils.py | 5 ++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/test_core.py b/tests/test_core.py index 2cb759918b..112c1efe57 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -377,3 +377,31 @@ def main(names: list[str] = typer.Option(None)): result = runner.invoke(app, [], default_map={"names": "not-a-list"}) assert result.exit_code == 2 assert "Invalid value" in result.output + + +def test_count_option_help_no_metavar() -> None: + """Regression test for https://github.com/fastapi/typer/issues/1869. + + count=True options should not show INTEGER in help since they don't take a value. + """ + app = typer.Typer() + + @app.command() + def main(verbose: int = typer.Option(0, count=True)): + """Count verbosity.""" + typer.echo(f"verbose={verbose}") + + result = runner.invoke(app, ["--help"]) + assert result.exit_code == 0 + # The help must not show INTEGER for a count option + assert "INTEGER" not in result.output + assert "--verbose" in result.output + + # Behaviour: --verbose increments + assert runner.invoke(app, ["--verbose"]).exit_code == 0 + + # Behaviour: --verbose 3 is rejected (count doesn't accept a value) + result = runner.invoke(app, ["--verbose", "3"]) + assert result.exit_code == 2 + assert "unexpected extra argument" in result.output + diff --git a/typer/core.py b/typer/core.py index 6868ab4355..a6c414b20e 100644 --- a/typer/core.py +++ b/typer/core.py @@ -743,6 +743,8 @@ def _extract_default_help_str( return _extract_default_help_str(self, ctx=ctx) def make_metavar(self, ctx: _click.Context) -> str: + if self.count: + return "" return super().make_metavar(ctx=ctx) def get_help_record(self, ctx: _click.Context) -> tuple[str, str] | None: diff --git a/typer/rich_utils.py b/typer/rich_utils.py index de68f60644..3a9cd8c950 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -397,9 +397,12 @@ def _print_options_panel( types_data = Text(style=STYLE_TYPES, overflow="fold") # Fetch type + is_count_option: bool = ( + isinstance(param, TyperOption) and param.count + ) if metavar_type and metavar_type != "BOOLEAN": types_data.append(metavar_type) - else: + elif not is_count_option: type_str = param.type.name.upper() if type_str != "BOOLEAN": types_data.append(type_str) From 06131d28dfe5d2276524d44741766f27ba6e56ef Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 18:30:12 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_core.py | 1 - typer/rich_utils.py | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 112c1efe57..9f24efa5c8 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -404,4 +404,3 @@ def main(verbose: int = typer.Option(0, count=True)): result = runner.invoke(app, ["--verbose", "3"]) assert result.exit_code == 2 assert "unexpected extra argument" in result.output - diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 3a9cd8c950..2202f98bb4 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -397,9 +397,7 @@ def _print_options_panel( types_data = Text(style=STYLE_TYPES, overflow="fold") # Fetch type - is_count_option: bool = ( - isinstance(param, TyperOption) and param.count - ) + is_count_option: bool = isinstance(param, TyperOption) and param.count if metavar_type and metavar_type != "BOOLEAN": types_data.append(metavar_type) elif not is_count_option: