diff --git a/tests/assets/print_modules.py b/tests/assets/print_modules.py new file mode 100644 index 0000000000..dbaffafaa7 --- /dev/null +++ b/tests/assets/print_modules.py @@ -0,0 +1,15 @@ +import sys + +import typer + +app = typer.Typer() + + +@app.command() +def main(): + for m in sys.modules: + print(m) + + +if __name__ == "__main__": + app() diff --git a/tests/test_rich_import.py b/tests/test_rich_import.py new file mode 100644 index 0000000000..f1c26bfe76 --- /dev/null +++ b/tests/test_rich_import.py @@ -0,0 +1,21 @@ +import subprocess +import sys +from pathlib import Path + +ACCEPTED_MODULES = {"rich._extension", "rich"} + + +def test_rich_not_imported_unnecessary(): + file_path = Path(__file__).parent / "assets/print_modules.py" + result = subprocess.run( + [sys.executable, "-m", "coverage", "run", str(file_path)], + capture_output=True, + encoding="utf-8", + ) + modules = result.stdout.splitlines() + modules = [ + module + for module in modules + if module not in ACCEPTED_MODULES and module.startswith("rich") + ] + assert not modules diff --git a/typer/cli.py b/typer/cli.py index 3fe3d3ee7f..c962cece79 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -15,7 +15,6 @@ import rich has_rich = True - from . import rich_utils except ImportError: # pragma: no cover has_rich = False @@ -275,6 +274,8 @@ def get_docs_for_click( def _parse_html(input_text: str) -> str: if not has_rich: # pragma: no cover return input_text + from . import rich_utils + return rich_utils.rich_to_html(input_text) diff --git a/typer/core.py b/typer/core.py index bb5aa48dd0..5355f2f890 100644 --- a/typer/core.py +++ b/typer/core.py @@ -33,8 +33,6 @@ try: import rich - from . import rich_utils - DEFAULT_MARKUP_MODE: MarkupMode = "rich" except ImportError: # pragma: no cover @@ -213,6 +211,8 @@ def _main( raise # Typer override if rich and rich_markup_mode is not None: + from . import rich_utils + rich_utils.rich_format_error(e) else: e.show() @@ -243,6 +243,8 @@ def _main( raise # Typer override if rich and rich_markup_mode is not None: + from . import rich_utils + rich_utils.rich_abort_error() else: click.echo(_("Aborted!"), file=sys.stderr) @@ -688,6 +690,8 @@ def main( def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: if not rich or self.rich_markup_mode is None: return super().format_help(ctx, formatter) + from . import rich_utils + return rich_utils.rich_format_help( obj=self, ctx=ctx, @@ -751,6 +755,8 @@ def main( def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: if not rich or self.rich_markup_mode is None: return super().format_help(ctx, formatter) + from . import rich_utils + return rich_utils.rich_format_help( obj=self, ctx=ctx, diff --git a/typer/main.py b/typer/main.py index 508d96617e..f48f1dcc95 100644 --- a/typer/main.py +++ b/typer/main.py @@ -50,11 +50,6 @@ try: import rich - from rich.traceback import Traceback - - from . import rich_utils - - console_stderr = rich_utils._get_rich_console(stderr=True) except ImportError: # pragma: no cover rich = None # type: ignore @@ -82,7 +77,9 @@ def except_hook( supress_internal_dir_names = [typer_path, click_path] exc = exc_value if rich: - from .rich_utils import MAX_WIDTH + from rich.traceback import Traceback + + from . import rich_utils rich_tb = Traceback.from_exception( type(exc), @@ -90,8 +87,9 @@ def except_hook( exc.__traceback__, show_locals=exception_config.pretty_exceptions_show_locals, suppress=supress_internal_dir_names, - width=MAX_WIDTH, + width=rich_utils.MAX_WIDTH, ) + console_stderr = rich_utils._get_rich_console(stderr=True) console_stderr.print(rich_tb) return tb_exc = traceback.TracebackException.from_exception(exc)