diff --git a/tests/test_suggest_commands.py b/tests/test_suggest_commands.py index 71f2398bb9..1582c69de2 100644 --- a/tests/test_suggest_commands.py +++ b/tests/test_suggest_commands.py @@ -1,6 +1,10 @@ +import pytest import typer +import typer.core from typer.testing import CliRunner +from tests.utils import needs_rich + runner = CliRunner() @@ -96,3 +100,35 @@ def delete(): # pragma: no cover assert result.exit_code != 0 assert "No such command" in result.output assert "Did you mean" not in result.output + + +@pytest.mark.parametrize( + "use_rich", + [ + pytest.param(False), + pytest.param(True, marks=needs_rich), + ], +) +def test_typo_suggestion_excludes_hidden_commands( + monkeypatch: pytest.MonkeyPatch, use_rich: bool +) -> None: + monkeypatch.setattr(typer.core, "HAS_RICH", use_rich) + app = typer.Typer() + + @app.command() + def secret_agent(): # pragma: no cover + typer.echo("Visible command") + + @app.command(hidden=True) + def secret_admin(): + typer.echo("Hidden command") + + result = runner.invoke(app, ["secret-admi"]) + assert result.exit_code != 0 + assert "No such command" in result.output + assert "'secret-agent'" in result.output + assert "'secret-admin'" not in result.output + + result = runner.invoke(app, ["secret-admin"]) + assert result.exit_code == 0 + assert "Hidden command" in result.output diff --git a/typer/core.py b/typer/core.py index 1bfc399505..ddd341167b 100644 --- a/typer/core.py +++ b/typer/core.py @@ -1181,7 +1181,11 @@ def resolve_command( return self._click_resolve_command(ctx, args) except _click.exceptions.UsageError as e: if self.suggest_commands: - available_commands = list(self.commands.keys()) + available_commands = [ + name + for name, command in self.commands.items() + if not command.hidden + ] if available_commands and args: typo = args[0] matches = get_close_matches(typo, available_commands)