Skip to content
Open
Show file tree
Hide file tree
Changes from 16 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
6 changes: 3 additions & 3 deletions tests/assets/cli/multi_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ def hello(name: str = "World", age: int = typer.Option(0, help="The age of the u
typer.echo(f"Hello {name}")


@sub_app.command()
@sub_app.command(rich_help_panel="Greet")
def hi(user: str = typer.Argument("World", help="The name of the user to greet")):
"""
Say Hi
"""


@sub_app.command()
@sub_app.command(rich_help_panel="Farewell")
def bye():
"""
Say bye
Expand All @@ -32,7 +32,7 @@ def bye():
app.add_typer(sub_app, name="sub")


@app.command()
@app.command(rich_help_panel="")
def top():
"""
Top command
Expand Down
6 changes: 6 additions & 0 deletions tests/assets/cli/multiapp-docs-title.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]...
**Commands**:

* `hello`: Say Hello

**Greet**:

* `hi`: Say Hi

**Farewell**:

* `bye`: Say bye

### `multiapp sub hello`
Expand Down
6 changes: 6 additions & 0 deletions tests/assets/cli/multiapp-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]...
**Commands**:

* `hello`: Say Hello

**Greet**:

* `hi`: Say Hi

**Farewell**:

* `bye`: Say bye

### `multiapp sub hello`
Expand Down
58 changes: 42 additions & 16 deletions typer/cli.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import importlib.util
import re
import sys
from collections import defaultdict
from itertools import chain
from pathlib import Path
from typing import Any, List, Optional
from typing import Any, Dict, List, Optional

import click
import typer
Expand Down Expand Up @@ -240,26 +242,50 @@ def get_docs_for_click(
if isinstance(obj, Group):
group = obj
commands = group.list_commands(ctx)
default_panel_name = "Commands"
if has_rich:
from . import rich_utils

default_panel_name = rich_utils.COMMANDS_PANEL_TITLE
if commands:
docs += "**Commands**:\n\n"
panel_to_commands: Dict[str, List[click.Command]] = defaultdict(list)
for command in commands:
command_obj = group.get_command(ctx, command)
assert command_obj
docs += f"* `{command_obj.name}`"
command_help = command_obj.get_short_help_str()
if command_help:
docs += f": {_parse_html(command_help)}"
panel_name = default_panel_name
if has_rich:
from . import rich_utils

panel_name = rich_utils.get_panel_name(
command_obj, default_panel_name
)
panel_to_commands[panel_name].append(command_obj)
if has_rich:
# Ensure that the ungrouped commands show up first
default_command_objs = panel_to_commands.pop(default_panel_name, [])
if len(default_command_objs) > 0:
panel_to_commands = {
default_panel_name: default_command_objs,
**panel_to_commands,
}
for panel_name, command_objs in panel_to_commands.items():
docs += f"**{panel_name}**:\n\n"
for command_obj in command_objs:
docs += f"* `{command_obj.name}`"
command_help = command_obj.get_short_help_str()
if command_help:
docs += f": {_parse_html(command_help)}"
docs += "\n"
docs += "\n"
docs += "\n"
for command in commands:
command_obj = group.get_command(ctx, command)
assert command_obj
use_prefix = ""
if command_name:
use_prefix += f"{command_name}"
docs += get_docs_for_click(
obj=command_obj, ctx=ctx, indent=indent + 1, call_prefix=use_prefix
)
for command_obj in chain.from_iterable(
command_objs for command_objs in panel_to_commands.values()
):
use_prefix = ""
if command_name:
use_prefix += f"{command_name}"
docs += get_docs_for_click(
obj=command_obj, ctx=ctx, indent=indent + 1, call_prefix=use_prefix
)
return docs


Expand Down
19 changes: 9 additions & 10 deletions typer/rich_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,14 +592,10 @@ def rich_format_help(
if getattr(param, "hidden", False):
continue
if isinstance(param, click.Argument):
panel_name = (
getattr(param, _RICH_HELP_PANEL_NAME, None) or ARGUMENTS_PANEL_TITLE
)
panel_name = get_panel_name(param, ARGUMENTS_PANEL_TITLE)
panel_to_arguments[panel_name].append(param)
elif isinstance(param, click.Option):
panel_name = (
getattr(param, _RICH_HELP_PANEL_NAME, None) or OPTIONS_PANEL_TITLE
)
panel_name = get_panel_name(param, OPTIONS_PANEL_TITLE)
panel_to_options[panel_name].append(param)
default_arguments = panel_to_arguments.get(ARGUMENTS_PANEL_TITLE, [])
_print_options_panel(
Expand Down Expand Up @@ -645,10 +641,7 @@ def rich_format_help(
for command_name in obj.list_commands(ctx):
command = obj.get_command(ctx, command_name)
if command and not command.hidden:
panel_name = (
getattr(command, _RICH_HELP_PANEL_NAME, None)
or COMMANDS_PANEL_TITLE
)
panel_name = get_panel_name(command, COMMANDS_PANEL_TITLE)
panel_to_commands[panel_name].append(command)

# Identify the longest command name in all panels
Expand Down Expand Up @@ -768,3 +761,9 @@ def get_traceback(
width=MAX_WIDTH,
)
return rich_tb


def get_panel_name(
obj: Union[click.Command, click.Argument, click.Option], default_name: str
) -> str:
return getattr(obj, _RICH_HELP_PANEL_NAME, None) or default_name
Loading