From ee6932cd08f2165e57f45f8cb6aaaee60f71a02f Mon Sep 17 00:00:00 2001 From: Kinuax Date: Thu, 9 May 2024 22:34:21 +0200 Subject: [PATCH 01/19] Add support for commands' rich_help_panel in generated docs --- typer/cli.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/typer/cli.py b/typer/cli.py index 70b9101f37..fefab8ef9a 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -1,13 +1,16 @@ 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, DefaultDict, List, Optional import click import typer import typer.core from click import Command, Group, Option +from typer.rich_utils import _RICH_HELP_PANEL_NAME, COMMANDS_PANEL_TITLE from . import __version__ @@ -240,19 +243,31 @@ def get_docs_for_click( group = obj commands = group.list_commands(ctx) if commands: - docs += "**Commands**:\n\n" + panel_to_commands: DefaultDict[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": {command_help}" + panel_name = ( + getattr(command_obj, _RICH_HELP_PANEL_NAME, None) + or COMMANDS_PANEL_TITLE + ) + panel_to_commands[panel_name].append(command_obj) + if default_command_objs := panel_to_commands.pop(COMMANDS_PANEL_TITLE, []): + panel_to_commands = { + COMMANDS_PANEL_TITLE: 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}`" + if command_help := command_obj.get_short_help_str(): + docs += f": {command_help}" + docs += "\n" docs += "\n" - docs += "\n" - for command in commands: - command_obj = group.get_command(ctx, command) - assert command_obj + 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}" From b8025124435b8c9ff3fae17d1505c8dd9010a665 Mon Sep 17 00:00:00 2001 From: Kinuax Date: Fri, 10 May 2024 06:51:28 +0200 Subject: [PATCH 02/19] Fix type --- typer/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/typer/cli.py b/typer/cli.py index fefab8ef9a..2b6596a8c5 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -4,7 +4,7 @@ from collections import defaultdict from itertools import chain from pathlib import Path -from typing import Any, DefaultDict, List, Optional +from typing import Any, Dict, List, Optional import click import typer @@ -243,7 +243,7 @@ def get_docs_for_click( group = obj commands = group.list_commands(ctx) if commands: - panel_to_commands: DefaultDict[str, List[click.Command]] = defaultdict(list) + panel_to_commands: Dict[str, List[click.Command]] = defaultdict(list) for command in commands: command_obj = group.get_command(ctx, command) assert command_obj From 80f27a3916304939f00cdc00dfd33fbb9b98c189 Mon Sep 17 00:00:00 2001 From: Kinuax Date: Fri, 10 May 2024 15:19:57 +0200 Subject: [PATCH 03/19] Add tests with combination of panels --- tests/assets/cli/multi_app.py | 16 ++++++++++++---- tests/assets/cli/multiapp-docs-title.md | 20 +++++++++++++++++++- tests/assets/cli/multiapp-docs.md | 20 +++++++++++++++++++- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/tests/assets/cli/multi_app.py b/tests/assets/cli/multi_app.py index 1442aa2442..3eadfd1882 100644 --- a/tests/assets/cli/multi_app.py +++ b/tests/assets/cli/multi_app.py @@ -5,7 +5,7 @@ variable = "Some text" -@sub_app.command() +@sub_app.command(rich_help_panel="Greet") def hello(name: str = "World", age: int = typer.Option(0, help="The age of the user")): """ Say Hello @@ -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 @@ -32,9 +32,17 @@ def bye(): app.add_typer(sub_app, name="sub") -@app.command() +@app.command(rich_help_panel="") def top(): """ Top command """ typer.echo("top") + + +@app.command(rich_help_panel="Commands") +def trivial(): + """ + Trivial command + """ + typer.echo("trivial") diff --git a/tests/assets/cli/multiapp-docs-title.md b/tests/assets/cli/multiapp-docs-title.md index e688a9ba91..70462bf561 100644 --- a/tests/assets/cli/multiapp-docs-title.md +++ b/tests/assets/cli/multiapp-docs-title.md @@ -20,6 +20,7 @@ The end * `sub` * `top`: Top command +* `trivial`: Trivial command ## `multiapp sub` @@ -33,9 +34,12 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]... * `--help`: Show this message and exit. -**Commands**: +**Farewell**: * `bye`: Say bye + +**Greet**: + * `hello`: Say Hello * `hi`: Say Hi @@ -100,3 +104,17 @@ $ multiapp top [OPTIONS] **Options**: * `--help`: Show this message and exit. + +## `multiapp trivial` + +Trivial command + +**Usage**: + +```console +$ multiapp trivial [OPTIONS] +``` + +**Options**: + +* `--help`: Show this message and exit. diff --git a/tests/assets/cli/multiapp-docs.md b/tests/assets/cli/multiapp-docs.md index ed4592f5c8..dffe29ade8 100644 --- a/tests/assets/cli/multiapp-docs.md +++ b/tests/assets/cli/multiapp-docs.md @@ -20,6 +20,7 @@ The end * `sub` * `top`: Top command +* `trivial`: Trivial command ## `multiapp sub` @@ -33,9 +34,12 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]... * `--help`: Show this message and exit. -**Commands**: +**Farewell**: * `bye`: Say bye + +**Greet**: + * `hello`: Say Hello * `hi`: Say Hi @@ -100,3 +104,17 @@ $ multiapp top [OPTIONS] **Options**: * `--help`: Show this message and exit. + +## `multiapp trivial` + +Trivial command + +**Usage**: + +```console +$ multiapp trivial [OPTIONS] +``` + +**Options**: + +* `--help`: Show this message and exit. From 760cf3cd07a028854c022fbd4d0b4385c736ae9d Mon Sep 17 00:00:00 2001 From: Kinuax Date: Fri, 17 May 2024 18:03:45 +0200 Subject: [PATCH 04/19] Avoid assignment expressions --- typer/cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/typer/cli.py b/typer/cli.py index 2b6596a8c5..3b262fc155 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -252,7 +252,8 @@ def get_docs_for_click( or COMMANDS_PANEL_TITLE ) panel_to_commands[panel_name].append(command_obj) - if default_command_objs := panel_to_commands.pop(COMMANDS_PANEL_TITLE, []): + default_command_objs = panel_to_commands.pop(COMMANDS_PANEL_TITLE, []) + if default_command_objs: panel_to_commands = { COMMANDS_PANEL_TITLE: default_command_objs, **panel_to_commands, @@ -261,7 +262,8 @@ def get_docs_for_click( docs += f"**{panel_name}**:\n\n" for command_obj in command_objs: docs += f"* `{command_obj.name}`" - if command_help := command_obj.get_short_help_str(): + command_help = command_obj.get_short_help_str() + if command_help: docs += f": {command_help}" docs += "\n" docs += "\n" From 99e1477b2f3734a8df12b456d875359c05b76375 Mon Sep 17 00:00:00 2001 From: Kinuax Date: Fri, 17 May 2024 18:34:42 +0200 Subject: [PATCH 05/19] Mix default and custom commands in same app --- tests/assets/cli/multi_app.py | 10 +------ tests/assets/cli/multiapp-docs-title.md | 36 +++++++++---------------- tests/assets/cli/multiapp-docs.md | 36 +++++++++---------------- 3 files changed, 25 insertions(+), 57 deletions(-) diff --git a/tests/assets/cli/multi_app.py b/tests/assets/cli/multi_app.py index 3eadfd1882..2c3e33ae26 100644 --- a/tests/assets/cli/multi_app.py +++ b/tests/assets/cli/multi_app.py @@ -5,7 +5,7 @@ variable = "Some text" -@sub_app.command(rich_help_panel="Greet") +@sub_app.command() def hello(name: str = "World", age: int = typer.Option(0, help="The age of the user")): """ Say Hello @@ -38,11 +38,3 @@ def top(): Top command """ typer.echo("top") - - -@app.command(rich_help_panel="Commands") -def trivial(): - """ - Trivial command - """ - typer.echo("trivial") diff --git a/tests/assets/cli/multiapp-docs-title.md b/tests/assets/cli/multiapp-docs-title.md index 70462bf561..0530044386 100644 --- a/tests/assets/cli/multiapp-docs-title.md +++ b/tests/assets/cli/multiapp-docs-title.md @@ -20,7 +20,6 @@ The end * `sub` * `top`: Top command -* `trivial`: Trivial command ## `multiapp sub` @@ -34,43 +33,46 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]... * `--help`: Show this message and exit. +**Commands**: + +* `hello`: Say Hello + **Farewell**: * `bye`: Say bye **Greet**: -* `hello`: Say Hello * `hi`: Say Hi -### `multiapp sub bye` +### `multiapp sub hello` -Say bye +Say Hello **Usage**: ```console -$ multiapp sub bye [OPTIONS] +$ multiapp sub hello [OPTIONS] ``` **Options**: +* `--name TEXT`: [default: World] +* `--age INTEGER`: The age of the user [default: 0] * `--help`: Show this message and exit. -### `multiapp sub hello` +### `multiapp sub bye` -Say Hello +Say bye **Usage**: ```console -$ multiapp sub hello [OPTIONS] +$ multiapp sub bye [OPTIONS] ``` **Options**: -* `--name TEXT`: [default: World] -* `--age INTEGER`: The age of the user [default: 0] * `--help`: Show this message and exit. ### `multiapp sub hi` @@ -104,17 +106,3 @@ $ multiapp top [OPTIONS] **Options**: * `--help`: Show this message and exit. - -## `multiapp trivial` - -Trivial command - -**Usage**: - -```console -$ multiapp trivial [OPTIONS] -``` - -**Options**: - -* `--help`: Show this message and exit. diff --git a/tests/assets/cli/multiapp-docs.md b/tests/assets/cli/multiapp-docs.md index dffe29ade8..d2a1e7d35c 100644 --- a/tests/assets/cli/multiapp-docs.md +++ b/tests/assets/cli/multiapp-docs.md @@ -20,7 +20,6 @@ The end * `sub` * `top`: Top command -* `trivial`: Trivial command ## `multiapp sub` @@ -34,43 +33,46 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]... * `--help`: Show this message and exit. +**Commands**: + +* `hello`: Say Hello + **Farewell**: * `bye`: Say bye **Greet**: -* `hello`: Say Hello * `hi`: Say Hi -### `multiapp sub bye` +### `multiapp sub hello` -Say bye +Say Hello **Usage**: ```console -$ multiapp sub bye [OPTIONS] +$ multiapp sub hello [OPTIONS] ``` **Options**: +* `--name TEXT`: [default: World] +* `--age INTEGER`: The age of the user [default: 0] * `--help`: Show this message and exit. -### `multiapp sub hello` +### `multiapp sub bye` -Say Hello +Say bye **Usage**: ```console -$ multiapp sub hello [OPTIONS] +$ multiapp sub bye [OPTIONS] ``` **Options**: -* `--name TEXT`: [default: World] -* `--age INTEGER`: The age of the user [default: 0] * `--help`: Show this message and exit. ### `multiapp sub hi` @@ -104,17 +106,3 @@ $ multiapp top [OPTIONS] **Options**: * `--help`: Show this message and exit. - -## `multiapp trivial` - -Trivial command - -**Usage**: - -```console -$ multiapp trivial [OPTIONS] -``` - -**Options**: - -* `--help`: Show this message and exit. From ac013b37a30fa3e6e0bd2cf38f6aa5677a4994c6 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Thu, 28 Aug 2025 17:14:23 +0200 Subject: [PATCH 06/19] update expected output according to new functionality on master --- tests/assets/cli/multiapp-docs.md | 32 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/assets/cli/multiapp-docs.md b/tests/assets/cli/multiapp-docs.md index 64aa92b8cc..5993127b0a 100644 --- a/tests/assets/cli/multiapp-docs.md +++ b/tests/assets/cli/multiapp-docs.md @@ -51,14 +51,14 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]... * `hello`: Say Hello -**Farewell**: - -* `bye`: Say bye - **Greet**: * `hi`: Say Hi +**Farewell**: + +* `bye`: Say bye + ### `multiapp sub hello` Say Hello @@ -75,20 +75,6 @@ $ multiapp sub hello [OPTIONS] * `--age INTEGER`: The age of the user [default: 0] * `--help`: Show this message and exit. -### `multiapp sub bye` - -Say bye - -**Usage**: - -```console -$ multiapp sub bye [OPTIONS] -``` - -**Options**: - -* `--help`: Show this message and exit. - ### `multiapp sub hi` Say Hi @@ -120,3 +106,13 @@ $ multiapp sub bye [OPTIONS] **Options**: * `--help`: Show this message and exit. + +**Usage**: + +```console +$ multiapp sub bye [OPTIONS] +``` + +**Options**: + +* `--help`: Show this message and exit. From 90d1b3dbd34b6c2e42fd1125a20a075caa333747 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Thu, 28 Aug 2025 17:16:42 +0200 Subject: [PATCH 07/19] remove duplicate part --- tests/assets/cli/multiapp-docs.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/assets/cli/multiapp-docs.md b/tests/assets/cli/multiapp-docs.md index 5993127b0a..d02c4d5187 100644 --- a/tests/assets/cli/multiapp-docs.md +++ b/tests/assets/cli/multiapp-docs.md @@ -106,13 +106,3 @@ $ multiapp sub bye [OPTIONS] **Options**: * `--help`: Show this message and exit. - -**Usage**: - -```console -$ multiapp sub bye [OPTIONS] -``` - -**Options**: - -* `--help`: Show this message and exit. From 6386af3fbe7b533ebe7a87a4b4688c1bc2f7535a Mon Sep 17 00:00:00 2001 From: svlandeg Date: Thu, 28 Aug 2025 17:21:06 +0200 Subject: [PATCH 08/19] fix output according to new behaviour on master --- tests/assets/cli/multiapp-docs-title.md | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/tests/assets/cli/multiapp-docs-title.md b/tests/assets/cli/multiapp-docs-title.md index d52f0592bb..8c2f941c79 100644 --- a/tests/assets/cli/multiapp-docs-title.md +++ b/tests/assets/cli/multiapp-docs-title.md @@ -51,14 +51,14 @@ $ multiapp sub [OPTIONS] COMMAND [ARGS]... * `hello`: Say Hello -**Farewell**: - -* `bye`: Say bye - **Greet**: * `hi`: Say Hi +**Farewell**: + +* `bye`: Say bye + ### `multiapp sub hello` Say Hello @@ -75,20 +75,6 @@ $ multiapp sub hello [OPTIONS] * `--age INTEGER`: The age of the user [default: 0] * `--help`: Show this message and exit. -### `multiapp sub bye` - -Say bye - -**Usage**: - -```console -$ multiapp sub bye [OPTIONS] -``` - -**Options**: - -* `--help`: Show this message and exit. - ### `multiapp sub hi` Say Hi From a0598b51f2be5e1460b3888b38432792916728e2 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Tue, 9 Sep 2025 16:16:46 +0200 Subject: [PATCH 09/19] ensure robustness against rich imports --- typer/cli.py | 50 +++++++++++++++++++++++++++------------------ typer/rich_utils.py | 17 +++++++-------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/typer/cli.py b/typer/cli.py index aaf1fa915c..9d2b218d1a 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -10,7 +10,6 @@ import typer import typer.core from click import Command, Group, Option -from typer.rich_utils import _RICH_HELP_PANEL_NAME, COMMANDS_PANEL_TITLE from . import __version__ @@ -251,22 +250,33 @@ 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: panel_to_commands: Dict[str, List[click.Command]] = defaultdict(list) for command in commands: command_obj = group.get_command(ctx, command) assert command_obj - panel_name = ( - getattr(command_obj, _RICH_HELP_PANEL_NAME, None) - or COMMANDS_PANEL_TITLE - ) + if has_rich: + from . import rich_utils + + panel_name = rich_utils.get_panel_name( + command_obj, default_panel_name + ) + else: + panel_name = default_panel_name panel_to_commands[panel_name].append(command_obj) - default_command_objs = panel_to_commands.pop(COMMANDS_PANEL_TITLE, []) - if default_command_objs: - panel_to_commands = { - COMMANDS_PANEL_TITLE: default_command_objs, - **panel_to_commands, - } + 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: @@ -276,15 +286,15 @@ def get_docs_for_click( docs += f": {_parse_html(command_help)}" docs += "\n" docs += "\n" - 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 - ) + 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 diff --git a/typer/rich_utils.py b/typer/rich_utils.py index d4c3676aea..145df608bb 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -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( @@ -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 @@ -768,3 +761,7 @@ def get_traceback( width=MAX_WIDTH, ) return rich_tb + + +def get_panel_name(obj, default_name: str): + return getattr(obj, _RICH_HELP_PANEL_NAME, None) or default_name From 7d3e71c67df8f73efa0cb02262b89cc137eb914b Mon Sep 17 00:00:00 2001 From: svlandeg Date: Tue, 9 Sep 2025 16:22:13 +0200 Subject: [PATCH 10/19] fix type annotations --- typer/rich_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 145df608bb..bace5be83a 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -763,5 +763,7 @@ def get_traceback( return rich_tb -def get_panel_name(obj, default_name: str): +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 From 354fe9b7e5a1a4ac53185f02df3f2675323d36cf Mon Sep 17 00:00:00 2001 From: svlandeg Date: Tue, 9 Sep 2025 16:29:39 +0200 Subject: [PATCH 11/19] cleanup --- typer/cli.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/typer/cli.py b/typer/cli.py index 9d2b218d1a..8446cdcc5d 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -260,14 +260,13 @@ def get_docs_for_click( for command in commands: command_obj = group.get_command(ctx, command) assert command_obj + panel_name = default_panel_name if has_rich: from . import rich_utils panel_name = rich_utils.get_panel_name( command_obj, default_panel_name ) - else: - panel_name = default_panel_name panel_to_commands[panel_name].append(command_obj) if has_rich: # Ensure that the ungrouped commands show up first From 59108e54e89b0eb764f3e920f5dd33c73cae114b Mon Sep 17 00:00:00 2001 From: Kinuax Date: Mon, 22 Sep 2025 14:46:05 +0200 Subject: [PATCH 12/19] Fix name --- typer/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/typer/cli.py b/typer/cli.py index ac22d80fcd..346ef86576 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -243,7 +243,7 @@ def get_docs_for_click( group = obj commands = group.list_commands(ctx) default_panel_name = "Commands" - if has_rich: + if HAS_RICH: from . import rich_utils default_panel_name = rich_utils.COMMANDS_PANEL_TITLE @@ -253,14 +253,14 @@ def get_docs_for_click( command_obj = group.get_command(ctx, command) assert command_obj panel_name = default_panel_name - if has_rich: + 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: + 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: From 9b4e73c6084d25921d6491171a3997dfaeb9e95b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 16:03:31 +0000 Subject: [PATCH 13/19] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typer/cli.py | 1 - 1 file changed, 1 deletion(-) diff --git a/typer/cli.py b/typer/cli.py index 91a7993013..303b3da960 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -2,7 +2,6 @@ import re import sys from collections import defaultdict -from itertools import chain from pathlib import Path from typing import Any, Optional From a7007dde64d9fee2e9a5d171637fda83285bc122 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 9 Jan 2026 17:16:41 +0100 Subject: [PATCH 14/19] fix separator --- tests/test_cli/test_doc.py | 2 +- typer/cli.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_cli/test_doc.py b/tests/test_cli/test_doc.py index 1da8bb73ef..1a090d263e 100644 --- a/tests/test_cli/test_doc.py +++ b/tests/test_cli/test_doc.py @@ -138,7 +138,7 @@ def test_doc_no_typer(): "run", "-m", "typer", - "tests/assets/cli/empty_script.py", + "tests.assets.cli.empty_script", "utils", "docs", ], diff --git a/typer/cli.py b/typer/cli.py index 91a7993013..658a5fb3f7 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -281,9 +281,9 @@ def get_docs_for_click( 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 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}" From bed0785bf4c90631c050a39a0ed1f84ca3a57006 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 9 Jan 2026 17:19:34 +0100 Subject: [PATCH 15/19] fix import --- typer/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/typer/cli.py b/typer/cli.py index d8676a18dc..658a5fb3f7 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -2,6 +2,7 @@ import re import sys from collections import defaultdict +from itertools import chain from pathlib import Path from typing import Any, Optional From c06352ac0bc67993141c345751af5f07f64ebfc3 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 9 Jan 2026 17:49:15 +0100 Subject: [PATCH 16/19] don't show the headers if Rich is disabled --- tests/assets/cli/multiapp-docs-norich.md | 102 +++++++++++++++++++++++ tests/test_cli/test_doc.py | 2 +- 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 tests/assets/cli/multiapp-docs-norich.md diff --git a/tests/assets/cli/multiapp-docs-norich.md b/tests/assets/cli/multiapp-docs-norich.md new file mode 100644 index 0000000000..67d02568db --- /dev/null +++ b/tests/assets/cli/multiapp-docs-norich.md @@ -0,0 +1,102 @@ +# `multiapp` + +Demo App + +**Usage**: + +```console +$ multiapp [OPTIONS] COMMAND [ARGS]... +``` + +**Options**: + +* `--install-completion`: Install completion for the current shell. +* `--show-completion`: Show completion for the current shell, to copy it or customize the installation. +* `--help`: Show this message and exit. + +The end + +**Commands**: + +* `top`: Top command +* `sub` + +## `multiapp top` + +Top command + +**Usage**: + +```console +$ multiapp top [OPTIONS] +``` + +**Options**: + +* `--help`: Show this message and exit. + +## `multiapp sub` + +**Usage**: + +```console +$ multiapp sub [OPTIONS] COMMAND [ARGS]... +``` + +**Options**: + +* `--help`: Show this message and exit. + +**Commands**: + +* `hello`: Say Hello +* `hi`: Say Hi +* `bye`: Say bye + +### `multiapp sub hello` + +Say Hello + +**Usage**: + +```console +$ multiapp sub hello [OPTIONS] +``` + +**Options**: + +* `--name TEXT`: [default: World] +* `--age INTEGER`: The age of the user [default: 0] +* `--help`: Show this message and exit. + +### `multiapp sub hi` + +Say Hi + +**Usage**: + +```console +$ multiapp sub hi [OPTIONS] [USER] +``` + +**Arguments**: + +* `[USER]`: The name of the user to greet [default: World] + +**Options**: + +* `--help`: Show this message and exit. + +### `multiapp sub bye` + +Say bye + +**Usage**: + +```console +$ multiapp sub bye [OPTIONS] +``` + +**Options**: + +* `--help`: Show this message and exit. diff --git a/tests/test_cli/test_doc.py b/tests/test_cli/test_doc.py index 1a090d263e..5c6781f6fa 100644 --- a/tests/test_cli/test_doc.py +++ b/tests/test_cli/test_doc.py @@ -104,7 +104,7 @@ def test_doc_no_rich(): capture_output=True, encoding="utf-8", ) - docs_path: Path = Path(__file__).parent.parent / "assets/cli/multiapp-docs.md" + docs_path: Path = Path(__file__).parent.parent / "assets/cli/multiapp-docs-norich.md" docs = docs_path.read_text() assert docs in result.stdout assert "**Arguments**" in result.stdout From d4c82b0f10a2a2121125512fa98ae50b490aef46 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 16:50:02 +0000 Subject: [PATCH 17/19] =?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_cli/test_doc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_cli/test_doc.py b/tests/test_cli/test_doc.py index 5c6781f6fa..439685225b 100644 --- a/tests/test_cli/test_doc.py +++ b/tests/test_cli/test_doc.py @@ -104,7 +104,9 @@ def test_doc_no_rich(): capture_output=True, encoding="utf-8", ) - docs_path: Path = Path(__file__).parent.parent / "assets/cli/multiapp-docs-norich.md" + docs_path: Path = ( + Path(__file__).parent.parent / "assets/cli/multiapp-docs-norich.md" + ) docs = docs_path.read_text() assert docs in result.stdout assert "**Arguments**" in result.stdout From ad2211bf322dbab293a6b6480220c7f430d90e69 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 9 Jan 2026 17:50:13 +0100 Subject: [PATCH 18/19] fix formatting --- tests/test_cli/test_doc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_cli/test_doc.py b/tests/test_cli/test_doc.py index 5c6781f6fa..439685225b 100644 --- a/tests/test_cli/test_doc.py +++ b/tests/test_cli/test_doc.py @@ -104,7 +104,9 @@ def test_doc_no_rich(): capture_output=True, encoding="utf-8", ) - docs_path: Path = Path(__file__).parent.parent / "assets/cli/multiapp-docs-norich.md" + docs_path: Path = ( + Path(__file__).parent.parent / "assets/cli/multiapp-docs-norich.md" + ) docs = docs_path.read_text() assert docs in result.stdout assert "**Arguments**" in result.stdout From 37a1513ea18db11447fee5a8409e7631406378e3 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 25 Feb 2026 17:17:40 +0100 Subject: [PATCH 19/19] use | instead of Union --- typer/rich_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 5fd340f9bd..c1519684e4 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -747,6 +747,6 @@ def get_traceback( def get_panel_name( - obj: Union[click.Command, click.Argument, click.Option], default_name: str + obj: click.Command | click.Argument | click.Option, default_name: str ) -> str: return getattr(obj, _RICH_HELP_PANEL_NAME, None) or default_name