Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions tests/test_cli_docs_hidden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Tests for `typer ... utils docs` Markdown output respecting hidden parameters/commands.

`utils docs` walks the Click command tree and must stay consistent with the interactive
`--help` text (Rich): anything marked `hidden=True` should not appear in generated docs.
"""

import click
import typer
from typer.cli import get_docs_for_click
from typer.main import get_command


def test_get_docs_for_click_omits_hidden_subcommands() -> None:
"""Hidden subcommands must not appear in the command list or get nested sections."""

app = typer.Typer()

@app.command()
def public_cmd() -> None:
"""Visible to users."""
pass

@app.command(hidden=True)
def secret_cmd() -> None:
"""Internal helper; should not be exported to Markdown."""
pass

click_obj = get_command(app)
with click.Context(click_obj, info_name="demo") as ctx:
md = get_docs_for_click(obj=click_obj, ctx=ctx, name="demo")

# Typer/Click expose CLI names with hyphens by default.
assert "`public-cmd`" in md
assert "secret-cmd" not in md


def test_get_docs_for_click_omits_hidden_options() -> None:
"""Hidden options should not appear under **Options** in generated Markdown."""

app = typer.Typer()

@app.command()
def main(
visible: str = typer.Option("", "--visible", help="Shown."),
_legacy: str = typer.Option("", "--legacy", hidden=True, help="Deprecated."),
) -> None:
pass

click_obj = get_command(app)
with click.Context(click_obj, info_name="demo") as ctx:
md = get_docs_for_click(obj=click_obj, ctx=ctx, name="demo")

assert "--visible" in md
assert "--legacy" not in md
34 changes: 26 additions & 8 deletions typer/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,15 @@ def get_docs_for_click(
docs += f"{command_name} "
docs += f"{' '.join(usage_pieces)}\n"
docs += "```\n\n"
# Parameters marked with hidden=True are intentionally omitted from the live CLI
# help rendered by Rich (see rich_format_help in rich_utils.py). Generated Markdown
# from `typer ... utils docs` should follow the same rules so published docs do not
# leak internal or experimental flags/commands that authors hid from --help.
args = []
opts = []
for param in obj.get_params(ctx):
if getattr(param, "hidden", False):
continue
rv = param.get_help_record(ctx)
if rv is not None:
if param.param_type_name == "argument":
Expand All @@ -244,21 +250,33 @@ def get_docs_for_click(
docs += f"{obj.epilog}\n\n"
if isinstance(obj, Group):
group = obj
commands = group.list_commands(ctx)
if commands:
# Subcommands registered with hidden=True still appear in list_commands() but
# are excluded from the command panels in rich_format_help. Mirror that here so
# the Markdown outline and nested sections match what users see when they run
# --help on each group.
visible_commands: list[str] = []
for cmd_name in group.list_commands(ctx):
command_obj = group.get_command(ctx, cmd_name)
if command_obj is None:
continue
if getattr(command_obj, "hidden", False):
continue
visible_commands.append(cmd_name)

if visible_commands:
docs += "**Commands**:\n\n"
for command in commands:
command_obj = group.get_command(ctx, command)
assert command_obj
for cmd_name in visible_commands:
command_obj = group.get_command(ctx, cmd_name)
assert command_obj is not None
docs += f"* `{command_obj.name}`"
command_help = command_obj.get_short_help_str()
if command_help:
docs += f": {_parse_html(to_parse, command_help)}"
docs += "\n"
docs += "\n"
for command in commands:
command_obj = group.get_command(ctx, command)
assert command_obj
for cmd_name in visible_commands:
command_obj = group.get_command(ctx, cmd_name)
assert command_obj is not None
use_prefix = ""
if command_name:
use_prefix += f"{command_name}"
Expand Down
Loading