Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
79ccdf1
Add rich_expand parameter
harkabeeparolus Dec 16, 2024
77029f1
Merge branch 'fastapi:master' into feature/rich_expand
harkabeeparolus Dec 17, 2024
8cc6f45
Add documenation
harkabeeparolus Dec 17, 2024
1e1a256
Merge branch 'feature/rich_expand' of https://github.com/harkabeeparo…
harkabeeparolus Dec 17, 2024
b97e79e
Merge branch 'master' into feature/rich_expand
harkabeeparolus Mar 25, 2025
03860a5
Merge branch 'master' into feature/rich_expand
svlandeg Apr 8, 2025
61e036b
Merge branch 'master' into feature/rich_expand
harkabeeparolus Nov 12, 2025
2855bbc
Fix AssertionError: Sum of ratios must be > 0
harkabeeparolus Nov 12, 2025
7f9e5a4
Add rich_expand to typer.run()
harkabeeparolus Nov 12, 2025
691a8e3
Merge branch 'master' into feature/rich_expand
svlandeg Nov 19, 2025
eeb9669
Use Union notation to avoid failing tests
svlandeg Nov 19, 2025
6cb94dd
Fix typo
svlandeg Nov 19, 2025
f6373a2
Revert "Add rich_expand to typer.run()"
harkabeeparolus Nov 19, 2025
b6d4511
Remove unneccessary defalt parameter values
harkabeeparolus Nov 19, 2025
8e3d318
Remove unnecessary default value
harkabeeparolus Nov 19, 2025
82db16f
Restore unneeded expand=False in options_table
harkabeeparolus Nov 19, 2025
f02b51d
Merge branch 'master' into feature/rich_expand
svlandeg Nov 26, 2025
633128e
move new section to the end of the page
svlandeg Nov 26, 2025
18e81cb
add tutorial009 example
svlandeg Nov 26, 2025
c4a8f33
Merge branch 'master' into feature/rich_expand
svlandeg Nov 26, 2025
784907c
update emoji
svlandeg Nov 26, 2025
28aab8b
show rich_expand=False results
svlandeg Nov 26, 2025
acb1b59
update example (simplify)
svlandeg Nov 26, 2025
b0d031f
revert
svlandeg Nov 26, 2025
b3b41ec
fix test
svlandeg Nov 26, 2025
565a032
Merge branch 'feature/rich_expand' of https://github.com/harkabeeparo…
svlandeg Nov 26, 2025
df3209c
fix outline
svlandeg Nov 26, 2025
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
39 changes: 39 additions & 0 deletions docs/tutorial/commands/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,42 @@ $ python main.py --help
```

</div>

## Expand or Fit

By default, the help panels all expand to match the width of your terminal window.

Sometimes, you might prefer that all panels fit their contents instead. This means that they will probably have different widths.

You can do this by initializing your Typer with `rich_expand=False`, like this:

{* docs_src/commands/help/tutorial009.py hl[5] *}

When you now check the `--help` option, it will look like:

<div class="termy">

```console
$ python main.py create --help

<b> </b><font color="#F4BF75"><b>Usage: </b></font><b>main.py create [OPTIONS] USERNAME [LASTNAME] </b>
<b> </b>
<font color="#A6E22E">Create</font> a new user. ✨

<font color="#A5A5A1">╭─ Arguments ──────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#F92672">*</font> username <font color="#F4BF75"><b>TEXT</b></font> The username <font color="#A6194C">[required]</font> │
<font color="#A5A5A1">╰──────────────────────────────────────────────────╯</font>
<font color="#A5A5A1">╭─ Secondary Arguments ─────────────────────╮</font>
<font color="#A5A5A1">│ lastname </font><font color="#A37F4E"><b>[LASTNAME]</b></font> The last name │
<font color="#A5A5A1">╰───────────────────────────────────────────╯</font>
<font color="#A5A5A1">╭─ Options ────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--force</b></font> <font color="#AE81FF"><b>--no-force</b></font> Force the creation <font color="#A6194C">[required]</font> │
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--help</b></font> Show this message and exit. │
<font color="#A5A5A1">╰──────────────────────────────────────────────────────────╯</font>
<font color="#A5A5A1">╭─ Additional Data ───────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--age</b></font> <font color="#F4BF75"><b>INTEGER</b></font> The age │</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--favorite-color</b></font> <font color="#F4BF75"><b>TEXT </b></font> The favorite color │</font>
<font color="#A5A5A1">╰─────────────────────────────────────────────────────╯</font>
```

</div>
39 changes: 39 additions & 0 deletions docs_src/commands/help/tutorial009.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import Union

import typer

app = typer.Typer(rich_markup_mode="rich", rich_expand=False)


@app.command()
def create(
username: str = typer.Argument(..., help="The username"),
lastname: str = typer.Argument(
"", help="The last name", rich_help_panel="Secondary Arguments"
),
force: bool = typer.Option(..., help="Force the creation"),
age: Union[int, None] = typer.Option(
None, help="The age", rich_help_panel="Additional Data"
),
favorite_color: Union[str, None] = typer.Option(
None,
help="The favorite color",
rich_help_panel="Additional Data",
),
):
"""
[green]Create[/green] a new user. :sparkles:
"""
print(f"Creating user: {username}")


@app.command(rich_help_panel="Utils and Configs")
def config(configuration: str):
"""
[blue]Configure[/blue] the system. :gear:
"""
print(f"Configuring the system with: {configuration}")


if __name__ == "__main__":
app()
39 changes: 39 additions & 0 deletions tests/test_tutorial/test_commands/test_help/test_tutorial009.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os
import subprocess
import sys

from typer.testing import CliRunner

from docs_src.commands.help import tutorial009 as mod

app = mod.app

runner = CliRunner()


def test_main_help():
result = runner.invoke(app, ["--help"])
assert result.exit_code == 0
assert "create" in result.output
assert "Create a new user. ✨" in result.output
assert "Utils and Configs" in result.output
assert "config" in result.output
assert "Configure the system. ⚙" in result.output


def test_call():
# Mainly for coverage
result = runner.invoke(app, ["create", "Morty", "--force"])
assert result.exit_code == 0
result = runner.invoke(app, ["config", "Morty"])
assert result.exit_code == 0


def test_script():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
env={**os.environ, "PYTHONIOENCODING": "utf-8"},
)
assert "Usage" in result.stdout
11 changes: 10 additions & 1 deletion typer/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def _main(
standalone_mode: bool = True,
windows_expand_args: bool = True,
rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE,
rich_expand: bool,
**extra: Any,
) -> Any:
# Typer override, duplicated from click.main() to handle custom rich exceptions
Expand Down Expand Up @@ -212,7 +213,7 @@ def _main(
if HAS_RICH and rich_markup_mode is not None:
from . import rich_utils

rich_utils.rich_format_error(e)
rich_utils.rich_format_error(e, expand=rich_expand)
else:
e.show()
# Typer override end
Expand Down Expand Up @@ -674,6 +675,7 @@ def __init__(
# Rich settings
rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE,
rich_help_panel: Union[str, None] = None,
rich_expand: bool = True,
) -> None:
super().__init__(
name=name,
Expand All @@ -691,6 +693,7 @@ def __init__(
)
self.rich_markup_mode: MarkupMode = rich_markup_mode
self.rich_help_panel = rich_help_panel
self.rich_expand = rich_expand

def format_options(
self, ctx: click.Context, formatter: click.HelpFormatter
Expand Down Expand Up @@ -724,6 +727,7 @@ def main(
standalone_mode=standalone_mode,
windows_expand_args=windows_expand_args,
rich_markup_mode=self.rich_markup_mode,
rich_expand=self.rich_expand,
**extra,
)

Expand All @@ -736,6 +740,7 @@ def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> Non
obj=self,
ctx=ctx,
markup_mode=self.rich_markup_mode,
expand=self.rich_expand,
)


Expand All @@ -750,12 +755,14 @@ def __init__(
# Rich settings
rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE,
rich_help_panel: Union[str, None] = None,
rich_expand: bool = True,
suggest_commands: bool = True,
**attrs: Any,
) -> None:
super().__init__(name=name, commands=commands, **attrs)
self.rich_markup_mode: MarkupMode = rich_markup_mode
self.rich_help_panel = rich_help_panel
self.rich_expand = rich_expand
self.suggest_commands = suggest_commands

def format_options(
Expand Down Expand Up @@ -808,6 +815,7 @@ def main(
standalone_mode=standalone_mode,
windows_expand_args=windows_expand_args,
rich_markup_mode=self.rich_markup_mode,
rich_expand=self.rich_expand,
**extra,
)

Expand All @@ -820,6 +828,7 @@ def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> Non
obj=self,
ctx=ctx,
markup_mode=self.rich_markup_mode,
expand=self.rich_expand,
)

def list_commands(self, ctx: click.Context) -> List[str]:
Expand Down
10 changes: 10 additions & 0 deletions typer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def __init__(
add_completion: bool = True,
# Rich settings
rich_markup_mode: MarkupMode = Default(DEFAULT_MARKUP_MODE),
rich_expand: bool = True,
rich_help_panel: Union[str, None] = Default(None),
suggest_commands: bool = True,
pretty_exceptions_enable: bool = True,
Expand All @@ -144,6 +145,7 @@ def __init__(
):
self._add_completion = add_completion
self.rich_markup_mode: MarkupMode = rich_markup_mode
self.rich_expand = rich_expand
self.rich_help_panel = rich_help_panel
self.suggest_commands = suggest_commands
self.pretty_exceptions_enable = pretty_exceptions_enable
Expand Down Expand Up @@ -334,6 +336,7 @@ def get_group(typer_instance: Typer) -> TyperGroup:
TyperInfo(typer_instance),
pretty_exceptions_short=typer_instance.pretty_exceptions_short,
rich_markup_mode=typer_instance.rich_markup_mode,
rich_expand=typer_instance.rich_expand,
suggest_commands=typer_instance.suggest_commands,
)
return group
Expand Down Expand Up @@ -367,6 +370,7 @@ def get_command(typer_instance: Typer) -> click.Command:
single_command,
pretty_exceptions_short=typer_instance.pretty_exceptions_short,
rich_markup_mode=typer_instance.rich_markup_mode,
rich_expand=typer_instance.rich_expand,
)
if typer_instance._add_completion:
click_command.params.append(click_install_param)
Expand Down Expand Up @@ -463,6 +467,7 @@ def get_group_from_info(
pretty_exceptions_short: bool,
suggest_commands: bool,
rich_markup_mode: MarkupMode,
rich_expand: bool,
) -> TyperGroup:
assert group_info.typer_instance, (
"A Typer instance is needed to generate a Click Group"
Expand All @@ -473,6 +478,7 @@ def get_group_from_info(
command_info=command_info,
pretty_exceptions_short=pretty_exceptions_short,
rich_markup_mode=rich_markup_mode,
rich_expand=rich_expand,
)
if command.name:
commands[command.name] = command
Expand All @@ -481,6 +487,7 @@ def get_group_from_info(
sub_group_info,
pretty_exceptions_short=pretty_exceptions_short,
rich_markup_mode=rich_markup_mode,
rich_expand=rich_expand,
suggest_commands=suggest_commands,
)
if sub_group.name:
Expand Down Expand Up @@ -528,6 +535,7 @@ def get_group_from_info(
hidden=solved_info.hidden,
deprecated=solved_info.deprecated,
rich_markup_mode=rich_markup_mode,
rich_expand=rich_expand,
# Rich settings
rich_help_panel=solved_info.rich_help_panel,
suggest_commands=suggest_commands,
Expand Down Expand Up @@ -563,6 +571,7 @@ def get_command_from_info(
*,
pretty_exceptions_short: bool,
rich_markup_mode: MarkupMode,
rich_expand: bool,
) -> click.Command:
assert command_info.callback, "A command must have a callback function"
name = command_info.name or get_command_name(command_info.callback.__name__)
Expand Down Expand Up @@ -597,6 +606,7 @@ def get_command_from_info(
hidden=command_info.hidden,
deprecated=command_info.deprecated,
rich_markup_mode=rich_markup_mode,
rich_expand=rich_expand,
# Rich settings
rich_help_panel=command_info.rich_help_panel,
)
Expand Down
Loading
Loading