diff --git a/docs/tutorial/commands/help.md b/docs/tutorial/commands/help.md index b9501b72ee..5a6668038a 100644 --- a/docs/tutorial/commands/help.md +++ b/docs/tutorial/commands/help.md @@ -208,7 +208,7 @@ Then you can use more formatting in the docstrings and the `help` parameter for /// info -By default, `rich_markup_mode` is `None`, which disables any rich text formatting. +By default, `rich_markup_mode` is `None` if Rich is not installed, and `"rich"` if it is installed. In the latter case, you can set `rich_markup_mode` to `None` to disable rich text formatting. /// diff --git a/tests/test_rich_markup_mode.py b/tests/test_rich_markup_mode.py new file mode 100644 index 0000000000..d9fe5bae4b --- /dev/null +++ b/tests/test_rich_markup_mode.py @@ -0,0 +1,40 @@ +import typer +import typer.completion +from typer.testing import CliRunner + +runner = CliRunner() +rounded = ["╭", "─", "┬", "╮", "│", "├", "┼", "┤", "╰", "┴", "╯"] + + +def test_rich_markup_mode_none(): + app = typer.Typer(rich_markup_mode=None) + + @app.command() + def main(arg: str): + """Main function""" + print(f"Hello {arg}") + + assert app.rich_markup_mode is None + + result = runner.invoke(app, ["World"]) + assert "Hello World" in result.stdout + + result = runner.invoke(app, ["--help"]) + assert all(c not in result.stdout for c in rounded) + + +def test_rich_markup_mode_rich(): + app = typer.Typer(rich_markup_mode="rich") + + @app.command() + def main(arg: str): + """Main function""" + print(f"Hello {arg}") + + assert app.rich_markup_mode == "rich" + + result = runner.invoke(app, ["World"]) + assert "Hello World" in result.stdout + + result = runner.invoke(app, ["--help"]) + assert any(c in result.stdout for c in rounded) diff --git a/typer/core.py b/typer/core.py index 31fece5a76..c5cdbfee8d 100644 --- a/typer/core.py +++ b/typer/core.py @@ -31,15 +31,18 @@ else: from typing_extensions import Literal +MarkupMode = Literal["markdown", "rich", None] + try: import rich from . import rich_utils + DEFAULT_MARKUP_MODE: MarkupMode = "rich" + except ImportError: # pragma: no cover rich = None # type: ignore - -MarkupMode = Literal["markdown", "rich", None] + DEFAULT_MARKUP_MODE = None # Copy from click.parser._split_opt @@ -167,6 +170,7 @@ def _main( complete_var: Optional[str] = None, standalone_mode: bool = True, windows_expand_args: bool = True, + rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE, **extra: Any, ) -> Any: # Typer override, duplicated from click.main() to handle custom rich exceptions @@ -208,7 +212,7 @@ def _main( if not standalone_mode: raise # Typer override - if rich: + if rich and rich_markup_mode is not None: rich_utils.rich_format_error(e) else: e.show() @@ -238,7 +242,7 @@ def _main( if not standalone_mode: raise # Typer override - if rich: + if rich and rich_markup_mode is not None: rich_utils.rich_abort_error() else: click.echo(_("Aborted!"), file=sys.stderr) @@ -614,7 +618,7 @@ def __init__( hidden: bool = False, deprecated: bool = False, # Rich settings - rich_markup_mode: MarkupMode = None, + rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE, rich_help_panel: Union[str, None] = None, ) -> None: super().__init__( @@ -665,11 +669,12 @@ def main( complete_var=complete_var, standalone_mode=standalone_mode, windows_expand_args=windows_expand_args, + rich_markup_mode=self.rich_markup_mode, **extra, ) def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: - if not rich: + if not rich or self.rich_markup_mode is None: return super().format_help(ctx, formatter) return rich_utils.rich_format_help( obj=self, @@ -687,7 +692,7 @@ def __init__( Union[Dict[str, click.Command], Sequence[click.Command]] ] = None, # Rich settings - rich_markup_mode: MarkupMode = None, + rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE, rich_help_panel: Union[str, None] = None, **attrs: Any, ) -> None: @@ -727,11 +732,12 @@ def main( complete_var=complete_var, standalone_mode=standalone_mode, windows_expand_args=windows_expand_args, + rich_markup_mode=self.rich_markup_mode, **extra, ) def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: - if not rich: + if not rich or self.rich_markup_mode is None: return super().format_help(ctx, formatter) return rich_utils.rich_format_help( obj=self, diff --git a/typer/main.py b/typer/main.py index 9db26975ca..20b3c9bf0e 100644 --- a/typer/main.py +++ b/typer/main.py @@ -14,7 +14,14 @@ import click from .completion import get_completion_inspect_parameters -from .core import MarkupMode, TyperArgument, TyperCommand, TyperGroup, TyperOption +from .core import ( + DEFAULT_MARKUP_MODE, + MarkupMode, + TyperArgument, + TyperCommand, + TyperGroup, + TyperOption, +) from .models import ( AnyType, ArgumentInfo, @@ -132,7 +139,7 @@ def __init__( deprecated: bool = Default(False), add_completion: bool = True, # Rich settings - rich_markup_mode: MarkupMode = None, + rich_markup_mode: MarkupMode = Default(DEFAULT_MARKUP_MODE), rich_help_panel: Union[str, None] = Default(None), pretty_exceptions_enable: bool = True, pretty_exceptions_show_locals: bool = True,