From 96a61f892aaf1497ad77fa3a723ff9f2ce45a7f3 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Mon, 18 Nov 2024 18:11:38 +0100 Subject: [PATCH 01/13] =?UTF-8?q?=E2=9C=A8=20Allow=20gettext=20translation?= =?UTF-8?q?=20of=20help=20message=20(#886)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- typer/rich_utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 9ea5a14384..54909277f5 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -92,6 +92,7 @@ COMMANDS_PANEL_TITLE = _("Commands") ERRORS_PANEL_TITLE = _("Error") ABORTED_TEXT = _("Aborted.") +RICH_HELP = _("Try [blue]'{command_path} {help_option}'[/] for help.") MARKUP_MODE_MARKDOWN = "markdown" MARKUP_MODE_RICH = "rich" @@ -688,7 +689,9 @@ def rich_format_error(self: click.ClickException) -> None: if ctx is not None and ctx.command.get_help_option(ctx) is not None: console.print( - f"Try [blue]'{ctx.command_path} {ctx.help_option_names[0]}'[/] for help.", + RICH_HELP.format( + command_path=ctx.command_path, help_option=ctx.help_option_names[0] + ), style=STYLE_ERRORS_SUGGESTION, ) From 03ea87af7866a8667e85dd4b29dd786f4ba907d9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 18 Nov 2024 17:12:05 +0000 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 8841d98742..af7d038135 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,10 @@ ## Latest Changes +### Features + +* ✨ Allow gettext translation of help message. PR [#886](/~https://github.com/fastapi/typer/pull/886) by [@svlandeg](/~https://github.com/svlandeg). + ### Internal * ⬆ Bump ruff from 0.7.3 to 0.7.4. PR [#1051](/~https://github.com/fastapi/typer/pull/1051) by [@dependabot[bot]](/~https://github.com/apps/dependabot). From 14cac709e4de478a6fe9b4fef2a45ff8ebf934af Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Mon, 18 Nov 2024 18:15:07 +0100 Subject: [PATCH 03/13] =?UTF-8?q?=E2=9C=A8=20Support=20cp850=20encoding=20?= =?UTF-8?q?for=20auto-completion=20in=20PowerShell=20(#808)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typer/_completion_shared.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/typer/_completion_shared.py b/typer/_completion_shared.py index 4f40c143c0..cc0add992c 100644 --- a/typer/_completion_shared.py +++ b/typer/_completion_shared.py @@ -183,15 +183,15 @@ def install_powershell(*, prog_name: str, complete_var: str, shell: str) -> Path if isinstance(result.stdout, str): # pragma: no cover path_str = result.stdout if isinstance(result.stdout, bytes): - try: - # PowerShell would be predominant in Windows - path_str = result.stdout.decode("windows-1252") - except UnicodeDecodeError: # pragma: no cover + for encoding in ["windows-1252", "utf8", "cp850"]: try: - path_str = result.stdout.decode("utf8") - except UnicodeDecodeError: - click.echo("Couldn't decode the path automatically", err=True) - raise + path_str = result.stdout.decode(encoding) + break + except UnicodeDecodeError: # pragma: no cover + pass + if not path_str: # pragma: no cover + click.echo("Couldn't decode the path automatically", err=True) + raise click.exceptions.Exit(1) path_obj = Path(path_str.strip()) parent_dir: Path = path_obj.parent parent_dir.mkdir(parents=True, exist_ok=True) From a6167b381a5d270fb44848a492bea6f3547178c8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 18 Nov 2024 17:15:28 +0000 Subject: [PATCH 04/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index af7d038135..28f4239972 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ ### Features +* ✨ Support cp850 encoding for auto-completion in PowerShell. PR [#808](/~https://github.com/fastapi/typer/pull/808) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Allow gettext translation of help message. PR [#886](/~https://github.com/fastapi/typer/pull/886) by [@svlandeg](/~https://github.com/svlandeg). ### Internal From 5996fc18cb4cf29854b592061581f42957ce6257 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Mon, 18 Nov 2024 18:51:55 +0100 Subject: [PATCH 05/13] =?UTF-8?q?=E2=9C=A8=20Render=20Rich=20markup=20as?= =?UTF-8?q?=20HTML=20in=20Markdown=20docs=20(#847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- tests/assets/cli/rich_formatted_app.py | 22 ++++++++++++++++ tests/assets/cli/richformattedapp-docs.md | 21 +++++++++++++++ tests/test_cli/test_doc.py | 32 +++++++++++++++++++++++ typer/cli.py | 24 ++++++++++++++--- typer/core.py | 16 +++++++++--- typer/rich_utils.py | 14 ++++++++++ 6 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 tests/assets/cli/rich_formatted_app.py create mode 100644 tests/assets/cli/richformattedapp-docs.md diff --git a/tests/assets/cli/rich_formatted_app.py b/tests/assets/cli/rich_formatted_app.py new file mode 100644 index 0000000000..54d8a52267 --- /dev/null +++ b/tests/assets/cli/rich_formatted_app.py @@ -0,0 +1,22 @@ +import typer +from typing_extensions import Annotated + +app = typer.Typer(rich_markup_mode="rich") + + +@app.command(help="Say [bold red]hello[/bold red] to the user.") +def hello( + user_1: Annotated[ + str, + typer.Argument(help="The [bold]cool[/bold] name of the [green]user[/green]"), + ], + user_2: Annotated[str, typer.Argument(help="The world")] = "The World", + force: Annotated[ + bool, typer.Option(help="Force the welcome [red]message[/red]") + ] = False, +): + print(f"Hello {user_1} and {user_2}") # pragma: no cover + + +if __name__ == "__main__": + app() diff --git a/tests/assets/cli/richformattedapp-docs.md b/tests/assets/cli/richformattedapp-docs.md new file mode 100644 index 0000000000..678a2daf6f --- /dev/null +++ b/tests/assets/cli/richformattedapp-docs.md @@ -0,0 +1,21 @@ +# Awesome CLI + +Say hello to the user. + +**Usage**: + +```console +$ hello [OPTIONS] USER_1 [USER_2] +``` + +**Arguments**: + +* `USER_1`: The cool name of the user [required] +* `[USER_2]`: The world [default: The World] + +**Options**: + +* `--force / --no-force`: Force the welcome message [default: no-force] +* `--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. diff --git a/tests/test_cli/test_doc.py b/tests/test_cli/test_doc.py index 98e30631ba..f0d1d9b850 100644 --- a/tests/test_cli/test_doc.py +++ b/tests/test_cli/test_doc.py @@ -1,3 +1,4 @@ +import os import subprocess import sys from pathlib import Path @@ -140,3 +141,34 @@ def test_doc_file_not_existing(): encoding="utf-8", ) assert "Not a valid file or Python module:" in result.stderr + + +def test_doc_html_output(tmp_path: Path): + out_file: Path = tmp_path / "out.md" + result = subprocess.run( + [ + sys.executable, + "-m", + "coverage", + "run", + "-m", + "typer", + "tests.assets.cli.rich_formatted_app", + "utils", + "docs", + "--title", + "Awesome CLI", + "--output", + str(out_file), + ], + capture_output=True, + encoding="utf-8", + env={**os.environ, "PYTHONIOENCODING": "utf-8"}, + ) + docs_path: Path = ( + Path(__file__).parent.parent / "assets" / "cli" / "richformattedapp-docs.md" + ) + docs = docs_path.read_text(encoding="utf-8") + written_docs = out_file.read_text(encoding="utf-8") + assert docs in written_docs + assert "Docs saved to:" in result.stdout diff --git a/typer/cli.py b/typer/cli.py index 70b9101f37..3fe3d3ee7f 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -11,6 +11,16 @@ from . import __version__ +try: + import rich + + has_rich = True + from . import rich_utils + +except ImportError: # pragma: no cover + has_rich = False + rich = None # type: ignore + default_app_names = ("app", "cli", "main") default_func_names = ("main", "cli", "app") @@ -199,7 +209,7 @@ def get_docs_for_click( title = f"`{command_name}`" if command_name else "CLI" docs += f" {title}\n\n" if obj.help: - docs += f"{obj.help}\n\n" + docs += f"{_parse_html(obj.help)}\n\n" usage_pieces = obj.collect_usage_pieces(ctx) if usage_pieces: docs += "**Usage**:\n\n" @@ -223,7 +233,7 @@ def get_docs_for_click( for arg_name, arg_help in args: docs += f"* `{arg_name}`" if arg_help: - docs += f": {arg_help}" + docs += f": {_parse_html(arg_help)}" docs += "\n" docs += "\n" if opts: @@ -231,7 +241,7 @@ def get_docs_for_click( for opt_name, opt_help in opts: docs += f"* `{opt_name}`" if opt_help: - docs += f": {opt_help}" + docs += f": {_parse_html(opt_help)}" docs += "\n" docs += "\n" if obj.epilog: @@ -247,7 +257,7 @@ def get_docs_for_click( docs += f"* `{command_obj.name}`" command_help = command_obj.get_short_help_str() if command_help: - docs += f": {command_help}" + docs += f": {_parse_html(command_help)}" docs += "\n" docs += "\n" for command in commands: @@ -262,6 +272,12 @@ def get_docs_for_click( return docs +def _parse_html(input_text: str) -> str: + if not has_rich: # pragma: no cover + return input_text + return rich_utils.rich_to_html(input_text) + + @utils_app.command() def docs( ctx: typer.Context, diff --git a/typer/core.py b/typer/core.py index d9d651aaf8..8ec8b4b95d 100644 --- a/typer/core.py +++ b/typer/core.py @@ -366,8 +366,13 @@ def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]: if self.required: extra.append(_("required")) if extra: - extra_str = ";".join(extra) - help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + extra_str = "; ".join(extra) + extra_str = f"[{extra_str}]" + if rich is not None: + # This is needed for when we want to export to HTML + extra_str = rich.markup.escape(extra_str).strip() + + help = f"{help} {extra_str}" if help else f"{extra_str}" return name, help def make_metavar(self) -> str: @@ -554,7 +559,12 @@ def _write_opts(opts: Sequence[str]) -> str: if extra: extra_str = "; ".join(extra) - help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + extra_str = f"[{extra_str}]" + if rich is not None: + # This is needed for when we want to export to HTML + extra_str = rich.markup.escape(extra_str).strip() + + help = f"{help} {extra_str}" if help else f"{extra_str}" return ("; " if any_prefix_is_slash else " / ").join(rv), help diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 54909277f5..72b7122c42 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -709,3 +709,17 @@ def rich_abort_error() -> None: """Print richly formatted abort error.""" console = _get_rich_console(stderr=True) console.print(ABORTED_TEXT, style=STYLE_ABORTED) + + +def rich_to_html(input_text: str) -> str: + """Print the HTML version of a rich-formatted input string. + + This function does not provide a full HTML page, but can be used to insert + HTML-formatted text spans into a markdown file. + """ + console = Console(record=True, highlight=False) + + with console.capture(): + console.print(input_text, overflow="ignore", crop=False) + + return console.export_html(inline_styles=True, code_format="{code}").strip() From 2f9ce51b2716b22014d82f13cc1ecdfc34e75ad7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 18 Nov 2024 17:52:15 +0000 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 28f4239972..7a93d0d653 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ ### Features +* ✨ Render Rich markup as HTML in Markdown docs. PR [#847](/~https://github.com/fastapi/typer/pull/847) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Support cp850 encoding for auto-completion in PowerShell. PR [#808](/~https://github.com/fastapi/typer/pull/808) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Allow gettext translation of help message. PR [#886](/~https://github.com/fastapi/typer/pull/886) by [@svlandeg](/~https://github.com/svlandeg). From 376b907e3cd8f9cc05afa4f77b24e26d19f60e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 18 Nov 2024 23:06:44 +0100 Subject: [PATCH 07/13] =?UTF-8?q?=F0=9F=90=9B=20Fix=20printing=20HTML=20fr?= =?UTF-8?q?om=20Rich=20output=20(#1055)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typer/rich_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 72b7122c42..12b1cd8aad 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -1,6 +1,7 @@ # Extracted and modified from /~https://github.com/ewels/rich-click import inspect +import io import sys from collections import defaultdict from gettext import gettext as _ @@ -717,9 +718,8 @@ def rich_to_html(input_text: str) -> str: This function does not provide a full HTML page, but can be used to insert HTML-formatted text spans into a markdown file. """ - console = Console(record=True, highlight=False) + console = Console(record=True, highlight=False, file=io.StringIO()) - with console.capture(): - console.print(input_text, overflow="ignore", crop=False) + console.print(input_text, overflow="ignore", crop=False) return console.export_html(inline_styles=True, code_format="{code}").strip() From 20d4e5c76739ddb21e78d3f3166d6f73a09f5aad Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 18 Nov 2024 22:07:03 +0000 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 7a93d0d653..35436ae5a4 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,10 @@ * ✨ Support cp850 encoding for auto-completion in PowerShell. PR [#808](/~https://github.com/fastapi/typer/pull/808) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Allow gettext translation of help message. PR [#886](/~https://github.com/fastapi/typer/pull/886) by [@svlandeg](/~https://github.com/svlandeg). +### Refactors + +* 🐛 Fix printing HTML from Rich output. PR [#1055](/~https://github.com/fastapi/typer/pull/1055) by [@tiangolo](/~https://github.com/tiangolo). + ### Internal * ⬆ Bump ruff from 0.7.3 to 0.7.4. PR [#1051](/~https://github.com/fastapi/typer/pull/1051) by [@dependabot[bot]](/~https://github.com/apps/dependabot). From 603f39d2bfbe283b6138ff87188022d5535ae772 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Mon, 18 Nov 2024 23:14:33 +0100 Subject: [PATCH 09/13] =?UTF-8?q?=E2=9C=A8=20Remove=20Rich=20tags=20when?= =?UTF-8?q?=20showing=20completion=20text=20(#877)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../test_completion/test_completion_complete.py | 2 +- typer/completion.py | 16 +++++++++++++++- typer/rich_utils.py | 6 ++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/test_completion/test_completion_complete.py b/tests/test_completion/test_completion_complete.py index ea37f68546..e6d18b58a3 100644 --- a/tests/test_completion/test_completion_complete.py +++ b/tests/test_completion/test_completion_complete.py @@ -79,7 +79,7 @@ def test_completion_complete_subcommand_fish(): }, ) assert ( - "delete\tDelete a user with USERNAME.\ndelete-all\tDelete ALL users in the database." + "delete Delete a user with USERNAME.\ndelete-all Delete ALL users in the database." in result.stdout ) diff --git a/typer/completion.py b/typer/completion.py index 5b930bc20c..07ce83190c 100644 --- a/typer/completion.py +++ b/typer/completion.py @@ -15,6 +15,12 @@ except ImportError: # pragma: no cover shellingham = None +try: + import rich + +except ImportError: # pragma: no cover + rich = None # type: ignore + _click_patched = False @@ -139,9 +145,17 @@ def shell_complete( click.echo(comp.source()) return 0 + # Typer override to print the completion help msg with Rich if instruction == "complete": - click.echo(comp.complete()) + if not rich: # pragma: no cover + click.echo(comp.complete()) + else: + from . import rich_utils + + rich_utils.print_with_rich(comp.complete()) + return 0 + # Typer override end click.echo(f'Completion instruction "{instruction}" not supported.', err=True) return 1 diff --git a/typer/rich_utils.py b/typer/rich_utils.py index 12b1cd8aad..7d603da2d7 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -712,6 +712,12 @@ def rich_abort_error() -> None: console.print(ABORTED_TEXT, style=STYLE_ABORTED) +def print_with_rich(text: str) -> None: + """Print richly formatted message.""" + console = _get_rich_console() + console.print(text) + + def rich_to_html(input_text: str) -> str: """Print the HTML version of a rich-formatted input string. From f802688f1c35f9ba07c2e2ce5b9e845f01fff3b6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 18 Nov 2024 22:14:52 +0000 Subject: [PATCH 10/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 35436ae5a4..2bfe701315 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ ### Features +* ✨ Remove Rich tags when showing completion text. PR [#877](/~https://github.com/fastapi/typer/pull/877) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Render Rich markup as HTML in Markdown docs. PR [#847](/~https://github.com/fastapi/typer/pull/847) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Support cp850 encoding for auto-completion in PowerShell. PR [#808](/~https://github.com/fastapi/typer/pull/808) by [@svlandeg](/~https://github.com/svlandeg). * ✨ Allow gettext translation of help message. PR [#886](/~https://github.com/fastapi/typer/pull/886) by [@svlandeg](/~https://github.com/svlandeg). From 12459d21f2026dd806259702d934db0138196921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 18 Nov 2024 23:24:08 +0100 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20markdown=20includ?= =?UTF-8?q?es=20to=20use=20the=20new=20simpler=20format=20(#1054)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/tutorial/app-dir.md | 4 +- docs/tutorial/arguments/default.md | 44 +--- docs/tutorial/arguments/envvar.md | 66 +----- docs/tutorial/arguments/help.md | 180 +--------------- docs/tutorial/arguments/optional.md | 24 +-- docs/tutorial/commands/arguments.md | 4 +- docs/tutorial/commands/callback.md | 16 +- docs/tutorial/commands/context.md | 16 +- docs/tutorial/commands/help.md | 108 +--------- docs/tutorial/commands/index.md | 20 +- docs/tutorial/commands/name.md | 4 +- docs/tutorial/commands/one-or-multiple.md | 16 +- docs/tutorial/commands/options.md | 22 +- docs/tutorial/exceptions.md | 16 +- docs/tutorial/first-steps.md | 24 +-- docs/tutorial/launch.md | 8 +- .../arguments-with-multiple-values.md | 26 +-- .../multiple-values/multiple-options.md | 44 +--- .../options-with-multiple-values.md | 22 +- docs/tutorial/options-autocompletion.md | 198 +----------------- docs/tutorial/options/callback-and-context.md | 88 +------- docs/tutorial/options/help.md | 88 +------- docs/tutorial/options/name.md | 114 +--------- docs/tutorial/options/password.md | 44 +--- docs/tutorial/options/prompt.md | 66 +----- docs/tutorial/options/required.md | 24 +-- docs/tutorial/options/version.md | 66 +----- docs/tutorial/parameter-types/bool.md | 88 +------- docs/tutorial/parameter-types/custom-types.md | 30 +-- docs/tutorial/parameter-types/datetime.md | 26 +-- docs/tutorial/parameter-types/enum.md | 48 +---- docs/tutorial/parameter-types/file.md | 110 +--------- docs/tutorial/parameter-types/index.md | 4 +- docs/tutorial/parameter-types/number.md | 66 +----- docs/tutorial/parameter-types/path.md | 44 +--- docs/tutorial/parameter-types/uuid.md | 4 +- docs/tutorial/printing.md | 28 +-- docs/tutorial/progressbar.md | 24 +-- docs/tutorial/prompt.md | 16 +- docs/tutorial/subcommands/add-typer.md | 12 +- .../tutorial/subcommands/callback-override.md | 16 +- docs/tutorial/subcommands/name-and-help.md | 32 +-- .../subcommands/nested-subcommands.md | 40 +--- docs/tutorial/subcommands/single-file.md | 16 +- docs/tutorial/terminating.md | 12 +- docs/tutorial/testing.md | 50 +---- docs/tutorial/typer-command.md | 4 +- docs/tutorial/using-click.md | 16 +- mkdocs.yml | 2 +- requirements-docs.txt | 1 + 50 files changed, 186 insertions(+), 1855 deletions(-) diff --git a/docs/tutorial/app-dir.md b/docs/tutorial/app-dir.md index 440d1dc01a..72c23de528 100644 --- a/docs/tutorial/app-dir.md +++ b/docs/tutorial/app-dir.md @@ -2,9 +2,7 @@ You can get the application directory where you can, for example, save configuration files with `typer.get_app_dir()`: -```Python hl_lines="9" -{!../docs_src/app_dir/tutorial001.py!} -``` +{* docs_src/app_dir/tutorial001.py hl[9] *} It will give you a directory for storing configurations appropriate for your CLI program for the current user in each operating system. diff --git a/docs/tutorial/arguments/default.md b/docs/tutorial/arguments/default.md index 60a041abb1..e5e6ca22c7 100644 --- a/docs/tutorial/arguments/default.md +++ b/docs/tutorial/arguments/default.md @@ -8,27 +8,7 @@ That way the *CLI argument* will be optional *and also* have a default value. We can also use `typer.Argument()` to make a *CLI argument* have a default value other than `None`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/arguments/default/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/default/tutorial001.py!} -``` - -//// +{* docs_src/arguments/default/tutorial001_an.py hl[5] *} /// tip @@ -72,27 +52,7 @@ Hello Camila And we can even make the default value be dynamically generated by passing a function as the `default_factory` argument: -//// tab | Python 3.7+ - -```Python hl_lines="7-8 11" -{!> ../docs_src/arguments/default/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6-7 10" -{!> ../docs_src/arguments/default/tutorial002.py!} -``` - -//// +{* docs_src/arguments/default/tutorial002_an.py hl[7:8,11] *} In this case, we created the function `get_name` that will just return a random `str` each time. diff --git a/docs/tutorial/arguments/envvar.md b/docs/tutorial/arguments/envvar.md index a53d42685e..49bd247b6d 100644 --- a/docs/tutorial/arguments/envvar.md +++ b/docs/tutorial/arguments/envvar.md @@ -10,27 +10,7 @@ You can learn more about environment variables in the [Environment Variables](.. To do that, use the `envvar` parameter for `typer.Argument()`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/arguments/envvar/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/envvar/tutorial001.py!} -``` - -//// +{* docs_src/arguments/envvar/tutorial001_an.py hl[5] *} In this case, the *CLI argument* `name` will have a default value of `"World"`, but will also read any value passed to the environment variable `AWESOME_NAME` if no value is provided in the command line: @@ -75,27 +55,7 @@ Hello Mr. Czernobog You are not restricted to a single environment variable, you can declare a list of environment variables that could be used to get a value if it was not passed in the command line: -//// tab | Python 3.7+ - -```Python hl_lines="6" -{!> ../docs_src/arguments/envvar/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/envvar/tutorial002.py!} -``` - -//// +{* docs_src/arguments/envvar/tutorial002_an.py hl[6] *} Check it: @@ -130,27 +90,7 @@ Hello Mr. Anubis By default, environment variables used will be shown in the help text, but you can disable them with `show_envvar=False`: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/arguments/envvar/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/envvar/tutorial003.py!} -``` - -//// +{* docs_src/arguments/envvar/tutorial003_an.py hl[7] *} Check it: diff --git a/docs/tutorial/arguments/help.md b/docs/tutorial/arguments/help.md index 6203143871..2935a3e35f 100644 --- a/docs/tutorial/arguments/help.md +++ b/docs/tutorial/arguments/help.md @@ -4,9 +4,7 @@ In the *First Steps* section you saw how to add help for a CLI app/command by ad Here's how that last example looked like: -```Python -{!../docs_src/first_steps/tutorial006.py!} -``` +{* docs_src/first_steps/tutorial006.py *} Now that you also know how to use `typer.Argument()`, let's use it to add documentation specific for a *CLI argument*. @@ -14,27 +12,7 @@ Now that you also know how to use `typer.Argument()`, let's use it to add docume You can use the `help` parameter to add a help text for a *CLI argument*: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/arguments/help/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/help/tutorial001.py!} -``` - -//// +{* docs_src/arguments/help/tutorial001_an.py hl[5] *} And it will be used in the automatic `--help` option: @@ -59,27 +37,7 @@ Options: And of course, you can also combine that `help` with the docstring: -//// tab | Python 3.7+ - -```Python hl_lines="5-8" -{!> ../docs_src/arguments/help/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4-7" -{!> ../docs_src/arguments/help/tutorial002.py!} -``` - -//// +{* docs_src/arguments/help/tutorial002_an.py hl[5:8] *} And the `--help` option will combine all the information: @@ -106,27 +64,7 @@ Options: If you have a *CLI argument* with a default value, like `"World"`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/arguments/help/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/help/tutorial003.py!} -``` - -//// +{* docs_src/arguments/help/tutorial003_an.py hl[5] *} It will show that default value in the help text: @@ -151,27 +89,7 @@ Options: But you can disable that if you want to, with `show_default=False`: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/arguments/help/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/help/tutorial004.py!} -``` - -//// +{* docs_src/arguments/help/tutorial004_an.py hl[7] *} And then it won't show the default value: @@ -206,27 +124,7 @@ In **Typer** these default values are shown by default. 👀 You can use the same `show_default` to pass a custom string (instead of a `bool`) to customize the default value to be shown in the help text: -//// tab | Python 3.7+ - -```Python hl_lines="9" -{!> ../docs_src/arguments/help/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6" -{!> ../docs_src/arguments/help/tutorial005.py!} -``` - -//// +{* docs_src/arguments/help/tutorial005_an.py hl[9] *} And it will be used in the help text: @@ -271,27 +169,7 @@ But you can customize it with the `metavar` parameter for `typer.Argument()`. For example, let's say you don't want to have the default of `NAME`, you want to have `username`, in lowercase, and you really want ✨ emojis ✨ everywhere: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/arguments/help/tutorial006_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/help/tutorial006.py!} -``` - -//// +{* docs_src/arguments/help/tutorial006_an.py hl[5] *} Now the generated help text will have `✨username✨` instead of `NAME`: @@ -317,27 +195,7 @@ You might want to show the help information for *CLI arguments* in different pan If you have installed Rich as described in the docs for [Printing and Colors](../printing.md){.internal-link target=_blank}, you can set the `rich_help_panel` parameter to the name of the panel where you want this *CLI argument* to be shown: -//// tab | Python 3.7+ - -```Python hl_lines="8 12" -{!> ../docs_src/arguments/help/tutorial007_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="7 10" -{!> ../docs_src/arguments/help/tutorial007.py!} -``` - -//// +{* docs_src/arguments/help/tutorial007_an.py hl[8,12] *} Then, if you check the `--help` option, you will see a default panel named "`Arguments`" for the *CLI arguments* that don't have a custom `rich_help_panel`. @@ -380,27 +238,7 @@ If you want, you can make a *CLI argument* **not** show up in the `Arguments` se You will probably not want to do this normally, but it's possible: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/arguments/help/tutorial008_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/arguments/help/tutorial008.py!} -``` - -//// +{* docs_src/arguments/help/tutorial008_an.py hl[5] *} Check it: diff --git a/docs/tutorial/arguments/optional.md b/docs/tutorial/arguments/optional.md index e33b9cdc46..c9f35c1c3a 100644 --- a/docs/tutorial/arguments/optional.md +++ b/docs/tutorial/arguments/optional.md @@ -35,16 +35,12 @@ __init__.py test_tutorial In the [First Steps](../first-steps.md#add-a-cli-argument){.internal-link target=_blank} you saw how to add a *CLI argument*: -```Python hl_lines="4" -{!../docs_src/first_steps/tutorial002.py!} -``` +{* docs_src/first_steps/tutorial002.py hl[4] *} Now let's see an alternative way to create the same *CLI argument*: -```Python hl_lines="5" -{!> ../docs_src/arguments/optional/tutorial001_an.py!} -``` +{* docs_src/arguments/optional/tutorial001_an.py hl[5] *} /// info @@ -115,9 +111,7 @@ Now, finally what we came for, an optional *CLI argument*. To make a *CLI argument* optional, use `typer.Argument()` and pass a different "default" as the first parameter to `typer.Argument()`, for example `None`: -```Python hl_lines="7" -{!../docs_src/arguments/optional/tutorial002_an.py!} -``` +{* docs_src/arguments/optional/tutorial002_an.py hl[7] *} Now we have: @@ -190,9 +184,7 @@ Notice that "`Camila`" here is an optional *CLI argument*, not a *CLI option*, b Instead of using `Annotated`, you can use `typer.Argument()` as the default value: -```Python hl_lines="4" -{!> ../docs_src/arguments/optional/tutorial001.py!} -``` +{* docs_src/arguments/optional/tutorial001.py hl[4] *} /// tip @@ -226,15 +218,11 @@ If you hadn't seen that `...` before: it is a special single value, it is ../docs_src/arguments/optional/tutorial003.py!} -``` +{* docs_src/arguments/optional/tutorial003.py hl[4] *} And the same way, you can make it optional by passing a different `default` value, for example `None`: -```Python hl_lines="6" -{!> ../docs_src/arguments/optional/tutorial002.py!} -``` +{* docs_src/arguments/optional/tutorial002.py hl[6] *} Because the first parameter passed to `typer.Argument(default=None)` (the new "default" value) is `None`, **Typer** knows that this is an **optional** *CLI argument*, if no value is provided when calling it in the command line, it will have that default value of `None`. diff --git a/docs/tutorial/commands/arguments.md b/docs/tutorial/commands/arguments.md index 43bc423245..9b33fb0483 100644 --- a/docs/tutorial/commands/arguments.md +++ b/docs/tutorial/commands/arguments.md @@ -2,9 +2,7 @@ The same way as with a CLI application with a single command, subcommands (or just "commands") can also have their own *CLI arguments*: -```Python hl_lines="7 12" -{!../docs_src/commands/arguments/tutorial001.py!} -``` +{* docs_src/commands/arguments/tutorial001.py hl[7,12] *}
diff --git a/docs/tutorial/commands/callback.md b/docs/tutorial/commands/callback.md index ca10243c75..6e65cae7dc 100644 --- a/docs/tutorial/commands/callback.md +++ b/docs/tutorial/commands/callback.md @@ -12,9 +12,7 @@ But we can use `@app.callback()` for that. It's very similar to `@app.command()`, but it declares the *CLI parameters* for the main CLI application (before the commands): -```Python hl_lines="25 26 27 28 29 30 31 32" -{!../docs_src/commands/callback/tutorial001.py!} -``` +{* docs_src/commands/callback/tutorial001.py hl[25,26,27,28,29,30,31,32] *} Here we create a `callback` with a `--verbose` *CLI option*. @@ -81,9 +79,7 @@ Error: No such option: --verbose It's also possible to add a callback when creating the `typer.Typer()` app: -```Python hl_lines="4 5 8" -{!../docs_src/commands/callback/tutorial002.py!} -``` +{* docs_src/commands/callback/tutorial002.py hl[4,5,8] *} That achieves the same as with `@app.callback()`. @@ -104,9 +100,7 @@ Creating user: Camila If you added a callback when creating the `typer.Typer()` app, it's possible to override it with `@app.callback()`: -```Python hl_lines="11 12 13" -{!../docs_src/commands/callback/tutorial003.py!} -``` +{* docs_src/commands/callback/tutorial003.py hl[11,12,13] *} Now `new_callback()` will be the one used. @@ -130,9 +124,7 @@ You can also add a callback just to add the documentation in the docstring. It can be convenient especially if you have several lines of text, as the indentation will be automatically handled for you: -```Python hl_lines="8 9 10 11 12 13 14 15 16" -{!../docs_src/commands/callback/tutorial004.py!} -``` +{* docs_src/commands/callback/tutorial004.py hl[8,9,10,11,12,13,14,15,16] *} Now the callback will be used mainly to extract the docstring for the help text. diff --git a/docs/tutorial/commands/context.md b/docs/tutorial/commands/context.md index 2600225507..9e95b71c3d 100644 --- a/docs/tutorial/commands/context.md +++ b/docs/tutorial/commands/context.md @@ -14,9 +14,7 @@ For example, let's say that you want to execute some logic in a `Typer` callback You can get the name of the subcommand from the context: -```Python hl_lines="17 21" -{!../docs_src/commands/context/tutorial001.py!} -``` +{* docs_src/commands/context/tutorial001.py hl[17,21] *} Check it: @@ -46,9 +44,7 @@ And if no command is provided, the help message is shown. But we could make it run even without a subcommand with `invoke_without_command=True`: -```Python hl_lines="16" -{!../docs_src/commands/context/tutorial002.py!} -``` +{* docs_src/commands/context/tutorial002.py hl[16] *} Check it: @@ -78,9 +74,7 @@ For that, we can get the `typer.Context` and check if there's an invoked command If it's `None`, it means that we are not calling a subcommand but the main program (the callback) directly: -```Python hl_lines="17 21" -{!../docs_src/commands/context/tutorial003.py!} -``` +{* docs_src/commands/context/tutorial003.py hl[17,21] *} Check it: @@ -111,9 +105,7 @@ For example, you could keep additional *CLI parameters* not declared in your CLI Then you can access those extra raw *CLI parameters* as a `list` of `str` in `ctx.args`: -```Python hl_lines="7 9 10" -{!../docs_src/commands/context/tutorial004.py!} -``` +{* docs_src/commands/context/tutorial004.py hl[7,9,10] *}
diff --git a/docs/tutorial/commands/help.md b/docs/tutorial/commands/help.md index 5a6668038a..d5ec229d68 100644 --- a/docs/tutorial/commands/help.md +++ b/docs/tutorial/commands/help.md @@ -4,27 +4,7 @@ The same as before, you can add help for the commands in the docstrings and the And the `typer.Typer()` application receives a parameter `help` that you can pass with the main help text for your CLI program: -//// tab | Python 3.7+ - -```Python hl_lines="4 9-11 22 26-30 43 47-51 60-62" -{!> ../docs_src/commands/help/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="3 8-10 20 23-27 39 42-46 55-57" -{!> ../docs_src/commands/help/tutorial001.py!} -``` - -//// +{* docs_src/commands/help/tutorial001_an.py hl[4,9:11,22,26:30,43,47:51,60:62] *} Check it: @@ -112,9 +92,7 @@ You will also see how to use "Callbacks" later, and those include a way to add t You will probably be better adding the help text as a docstring to your functions, but if for some reason you wanted to overwrite it, you can use the `help` function argument passed to `@app.command()`: -```Python hl_lines="6 14" -{!../docs_src/commands/help/tutorial002.py!} -``` +{* docs_src/commands/help/tutorial002.py hl[6,14] *} Check it: @@ -148,9 +126,7 @@ There could be cases where you have a command in your app that you need to depre You can mark it with the parameter `deprecated=True`: -```Python hl_lines="14" -{!../docs_src/commands/help/tutorial003.py!} -``` +{* docs_src/commands/help/tutorial003.py hl[14] *} And when you show the `--help` option you will see it's marked as "`deprecated`": @@ -216,27 +192,7 @@ By default, `rich_markup_mode` is `None` if Rich is not installed, and `"rich"` If you set `rich_markup_mode="rich"` when creating the `typer.Typer()` app, you will be able to use Rich Console Markup in the docstring, and even in the help for the *CLI arguments* and options: -//// tab | Python 3.7+ - -```Python hl_lines="4 10 14-16 21 24 27" -{!> ../docs_src/commands/help/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="3 9 13-15 20 22 24" -{!> ../docs_src/commands/help/tutorial004.py!} -``` - -//// +{* docs_src/commands/help/tutorial004_an.py hl[4,10,14:16,21,24,27] *} With that, you can use Rich Console Markup to format the text in the docstring for the command `create`, make the word "`create`" bold and green, and even use an emoji. @@ -299,27 +255,7 @@ $ python main.py delete --help If you set `rich_markup_mode="markdown"` when creating the `typer.Typer()` app, you will be able to use Markdown in the docstring: -//// tab | Python 3.7+ - -```Python hl_lines="4 9 12-20 25 27-28" -{!> ../docs_src/commands/help/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="3 7 9-17 22 24-25" -{!> ../docs_src/commands/help/tutorial005.py!} -``` - -//// +{* docs_src/commands/help/tutorial005_an.py hl[4,9,12:20,25,27:28] *} With that, you can use Markdown to format the text in the docstring for the command `create`, make the word "`create`" bold, show a list of items, and even use an emoji. @@ -395,13 +331,7 @@ If you installed ../docs_src/commands/help/tutorial006.py!} -``` - -//// +{* docs_src/commands/help/tutorial006.py hl[22,30,38,46] *} Commands without a panel will be shown in the default panel `Commands`, and the rest will be shown in the next panels: @@ -442,27 +372,7 @@ The same way, you can configure the panels for *CLI arguments* and *CLI options* And of course, in the same application you can also set the `rich_help_panel` for commands. -//// tab | Python 3.7+ - -```Python hl_lines="15 21 27 37" -{!> ../docs_src/commands/help/tutorial007_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="12 16 21 30" -{!> ../docs_src/commands/help/tutorial007.py!} -``` - -//// +{* docs_src/commands/help/tutorial007_an.py hl[15,21,27,37] *} Then if you run the application you will see all the *CLI parameters* in their respective panels. @@ -540,9 +450,7 @@ You can see the custom panel for the commands for "`Utils and Configs`". If you need, you can also add an epilog section to the help of your commands: -```Python hl_lines="6" -{!../docs_src/commands/help/tutorial008.py!} -``` +{* docs_src/commands/help/tutorial008.py hl[6] *} And when you check the `--help` option it will look like: diff --git a/docs/tutorial/commands/index.md b/docs/tutorial/commands/index.md index f531c7cfb3..3d24751543 100644 --- a/docs/tutorial/commands/index.md +++ b/docs/tutorial/commands/index.md @@ -54,17 +54,13 @@ In the *CLI options* and *CLI argument* tutorials you have seen how to create a For example: -```Python hl_lines="9" -{!../docs_src/first_steps/tutorial002.py!} -``` +{* docs_src/first_steps/tutorial002.py hl[9] *} But that is actually a shortcut. Under the hood, **Typer** converts that to a CLI application with `typer.Typer()` and executes it. All that inside of `typer.run()`. There's also a more explicit way to achieve the same: -```Python hl_lines="3 6 12" -{!../docs_src/commands/index/tutorial001.py!} -``` +{* docs_src/commands/index/tutorial001.py hl[3,6,12] *} When you use `typer.run()`, **Typer** is doing more or less the same as above, it will: @@ -180,9 +176,7 @@ We'll have a command to `create` users and another command to `delete` them. To begin, let's say it can only create and delete one single predefined user: -```Python hl_lines="6 11" -{!../docs_src/commands/index/tutorial002.py!} -``` +{* docs_src/commands/index/tutorial002.py hl[6,11] *} Now we have a CLI application with 2 commands, `create` and `delete`: @@ -231,9 +225,7 @@ By default, we need to specify `--help` to get the command's help page. However, by setting `no_args_is_help=True` when defining the `typer.Typer()` application, the help function will be shown whenever no argument is given: -```Python hl_lines="3" -{!../docs_src/commands/index/tutorial003.py!} -``` +{* docs_src/commands/index/tutorial003.py hl[3] *} Now we can run this: @@ -264,9 +256,7 @@ Note that by design, **Typer** shows the commands in the order they've been decl So, if we take our original example, with `create` and `delete` commands, and reverse the order in the Python file: -```Python hl_lines="7 12" -{!../docs_src/commands/index/tutorial004.py!} -``` +{* docs_src/commands/index/tutorial004.py hl[7,12] *} Then we will see the `delete` command first in the help output: diff --git a/docs/tutorial/commands/name.md b/docs/tutorial/commands/name.md index 4f0faa047b..8fd36b3e95 100644 --- a/docs/tutorial/commands/name.md +++ b/docs/tutorial/commands/name.md @@ -17,9 +17,7 @@ And what if you wanted the command to still be named `create`? For this, you can set the name of the command in the first parameter for the `@app.command()` decorator: -```Python hl_lines="6 11" -{!../docs_src/commands/name/tutorial001.py!} -``` +{* docs_src/commands/name/tutorial001.py hl[6,11] *} Now, even though the functions are named `cli_create_user()` and `cli_delete_user()`, the commands will still be named `create` and `delete`: diff --git a/docs/tutorial/commands/one-or-multiple.md b/docs/tutorial/commands/one-or-multiple.md index 5f744c5a2b..b6afb92dc0 100644 --- a/docs/tutorial/commands/one-or-multiple.md +++ b/docs/tutorial/commands/one-or-multiple.md @@ -2,9 +2,7 @@ You might have noticed that if you create a single command, as in the first example: -```Python hl_lines="3 6 12" -{!../docs_src/commands/index/tutorial001.py!} -``` +{* docs_src/commands/index/tutorial001.py hl[3,6,12] *} **Typer** is smart enough to create a CLI application with that single function as the main CLI application, not as a command/subcommand: @@ -45,9 +43,7 @@ Notice that it doesn't show a command `main`, even though the function name is ` But if you add multiple commands, **Typer** will create one *CLI command* for each one of them: -```Python hl_lines="6 11" -{!../docs_src/commands/index/tutorial002.py!} -``` +{* docs_src/commands/index/tutorial002.py hl[6,11] *} Here we have 2 commands `create` and `delete`: @@ -84,9 +80,7 @@ Deleting user: Hiro Hamada If you want to create a CLI app with one single command but you still want it to be a command/subcommand you can just add a callback: -```Python hl_lines="11 12 13" -{!../docs_src/commands/one_or_multiple/tutorial001.py!} -``` +{* docs_src/commands/one_or_multiple/tutorial001.py hl[11,12,13] *} And now your CLI program will have a single command. @@ -121,9 +115,7 @@ Creating user: Hiro Hamada Now that you are using a callback just to have a single command, you might as well use it to add documentation for your app: -```Python hl_lines="11 12 13 14 15 16 17" -{!../docs_src/commands/one_or_multiple/tutorial002.py!} -``` +{* docs_src/commands/one_or_multiple/tutorial002.py hl[11,12,13,14,15,16,17] *} And now the docstring from the callback will be used as the help text: diff --git a/docs/tutorial/commands/options.md b/docs/tutorial/commands/options.md index a9c21b66b9..1d5567f876 100644 --- a/docs/tutorial/commands/options.md +++ b/docs/tutorial/commands/options.md @@ -4,27 +4,7 @@ Commands can also have their own *CLI options*. In fact, each command can have different *CLI arguments* and *CLI options*: -//// tab | Python 3.7+ - -```Python hl_lines="8 14-17 27-29 38" -{!> ../docs_src/commands/options/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="7 13-14 24 33" -{!> ../docs_src/commands/options/tutorial001.py!} -``` - -//// +{* docs_src/commands/options/tutorial001_an.py hl[8,14:17,27:29,38] *} Here we have multiple commands, with different *CLI parameters*: diff --git a/docs/tutorial/exceptions.md b/docs/tutorial/exceptions.md index 84dbac602c..43ca2d0f6d 100644 --- a/docs/tutorial/exceptions.md +++ b/docs/tutorial/exceptions.md @@ -8,9 +8,7 @@ Typer does some tricks to help you detect those errors quickly. Let's take this example broken app: -```Python hl_lines="5" -{!../docs_src/exceptions/tutorial001.py!} -``` +{* docs_src/exceptions/tutorial001.py hl[5] *} This code is broken because you can't sum a string and a number (`name + 3`). @@ -87,9 +85,7 @@ But if it was something like a password, you would have liked to hide it. In that case, you can create the `typer.Typer()` application explicitly and set the parameter `pretty_exceptions_show_locals=False`: -```Python hl_lines="3" -{!../docs_src/exceptions/tutorial002.py!} -``` +{* docs_src/exceptions/tutorial002.py hl[3] *} And now when you run it, you will see the error without the local variables: @@ -122,9 +118,7 @@ Being able to see the values of local variables is normally very **helpful** to If you want to show the full exception, including the parts in Typer and Click, you can use the parameter `pretty_exceptions_short=False`: -```Python hl_lines="3" -{!../docs_src/exceptions/tutorial003.py!} -``` +{* docs_src/exceptions/tutorial003.py hl[3] *} Now when you run it, you will see the whole output: @@ -206,9 +200,7 @@ $ python main.py You can also entirely disable pretty exceptions with the parameter `pretty_exceptions_enable=False`: -```Python hl_lines="3" -{!../docs_src/exceptions/tutorial004.py!} -``` +{* docs_src/exceptions/tutorial004.py hl[3] *} And now you will see the full standard exception as with any other Python program: diff --git a/docs/tutorial/first-steps.md b/docs/tutorial/first-steps.md index 53dc5eab4d..1f4fc35e1a 100644 --- a/docs/tutorial/first-steps.md +++ b/docs/tutorial/first-steps.md @@ -4,9 +4,7 @@ The simplest **Typer** file could look like this: -```Python -{!../docs_src/first_steps/tutorial001.py!} -``` +{* docs_src/first_steps/tutorial001.py *} Copy that to a file `main.py`. @@ -63,9 +61,7 @@ They are a bit different from **CLI options** that you will see later below. Update the previous example with an argument `name`: -```Python hl_lines="4 5" -{!../docs_src/first_steps/tutorial002.py!} -``` +{* docs_src/first_steps/tutorial002.py hl[4,5] *}
@@ -107,9 +103,7 @@ Now let's say we want to have the name and last name separated. So, extend that to have 2 arguments, `name` and `lastname`: -```Python hl_lines="4 5" -{!../docs_src/first_steps/tutorial003.py!} -``` +{* docs_src/first_steps/tutorial003.py hl[4,5] *}
@@ -234,9 +228,7 @@ This one doesn't receive any values. But *CLI options* can also receive values l Now add a `--formal` *CLI option*: -```Python hl_lines="4 5" -{!../docs_src/first_steps/tutorial004.py!} -``` +{* docs_src/first_steps/tutorial004.py hl[4,5] *} Here `formal` is a `bool` that is `False` by default. @@ -297,9 +289,7 @@ Good day Ms. Camila Gutiérrez. To convert the `lastname` from a *CLI argument* to a *CLI option*, give it a default value of `""`: -```Python hl_lines="4" -{!../docs_src/first_steps/tutorial005.py!} -``` +{* docs_src/first_steps/tutorial005.py hl[4] *} As `lastname` now has a default value of `""` (an empty string) it is no longer required in the function, and **Typer** will now by default make it an optional *CLI option*. @@ -370,9 +360,7 @@ Hello Camila Gutiérrez If you add a docstring to your function it will be used in the help text: -```Python hl_lines="5 6 7 8 9" -{!../docs_src/first_steps/tutorial006.py!} -``` +{* docs_src/first_steps/tutorial006.py hl[5,6,7,8,9] *} Now see it with the `--help` option: diff --git a/docs/tutorial/launch.md b/docs/tutorial/launch.md index 935bd7e632..740d7efae6 100644 --- a/docs/tutorial/launch.md +++ b/docs/tutorial/launch.md @@ -4,9 +4,7 @@ You can launch applications from your CLI program with `typer.launch()`. It will launch the appropriate application depending on the URL or file type you pass it: -```Python hl_lines="6" -{!../docs_src/launch/tutorial001.py!} -``` +{* docs_src/launch/tutorial001.py hl[6] *} Check it: @@ -26,9 +24,7 @@ Opening Typer docs You can also make the operating system open the file browser indicating where a file is located with `locate=True`: -```Python hl_lines="17" -{!../docs_src/launch/tutorial002.py!} -``` +{* docs_src/launch/tutorial002.py hl[17] *} /// tip diff --git a/docs/tutorial/multiple-values/arguments-with-multiple-values.md b/docs/tutorial/multiple-values/arguments-with-multiple-values.md index b48484c105..97af5e0edf 100644 --- a/docs/tutorial/multiple-values/arguments-with-multiple-values.md +++ b/docs/tutorial/multiple-values/arguments-with-multiple-values.md @@ -4,9 +4,7 @@ You can define the type of a *CLI argument* using `typing.List`. -```Python hl_lines="7" -{!../docs_src/multiple_values/arguments_with_multiple_values/tutorial001.py!} -``` +{* docs_src/multiple_values/arguments_with_multiple_values/tutorial001.py hl[7] *} And then you can pass it as many *CLI arguments* of that type as you want: @@ -39,27 +37,7 @@ A `List` can only be used in the last command (if there are subcommands), as thi If you want a specific number of values and types, you can use a tuple, and it can even have default values: -//// tab | Python 3.7+ - -```Python hl_lines="8-10" -{!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="7-8" -{!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002.py!} -``` - -//// +{* docs_src/multiple_values/arguments_with_multiple_values/tutorial002_an.py hl[8:10] *} Check it: diff --git a/docs/tutorial/multiple-values/multiple-options.md b/docs/tutorial/multiple-values/multiple-options.md index 0c876eab52..ef03e13c08 100644 --- a/docs/tutorial/multiple-values/multiple-options.md +++ b/docs/tutorial/multiple-values/multiple-options.md @@ -6,27 +6,7 @@ For example, let's say you want to accept several users in a single execution. For this, use the standard Python `typing.List` to declare it as a `list` of `str`: -//// tab | Python 3.7+ - -```Python hl_lines="1 7" -{!> ../docs_src/multiple_values/multiple_options/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="1 6" -{!> ../docs_src/multiple_values/multiple_options/tutorial001.py!} -``` - -//// +{* docs_src/multiple_values/multiple_options/tutorial001_an.py hl[1,7] *} You will receive the values as you declared them, as a `list` of `str`. @@ -60,27 +40,7 @@ Processing user: Morty The same way, you can use other types and they will be converted by **Typer** to their declared type: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/multiple_values/multiple_options/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6" -{!> ../docs_src/multiple_values/multiple_options/tutorial002.py!} -``` - -//// +{* docs_src/multiple_values/multiple_options/tutorial002_an.py hl[7] *} Check it: diff --git a/docs/tutorial/multiple-values/options-with-multiple-values.md b/docs/tutorial/multiple-values/options-with-multiple-values.md index 1d3f5deff4..8f37d2df51 100644 --- a/docs/tutorial/multiple-values/options-with-multiple-values.md +++ b/docs/tutorial/multiple-values/options-with-multiple-values.md @@ -6,27 +6,7 @@ You can set the number of values and types to anything you want, but it has to b For this, use the standard Python `typing.Tuple`: -//// tab | Python 3.7+ - -```Python hl_lines="1 7" -{!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="1 6" -{!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001.py!} -``` - -//// +{* docs_src/multiple_values/options_with_multiple_values/tutorial001_an.py hl[1,7] *} Each of the internal types defines the type of each value in the tuple. diff --git a/docs/tutorial/options-autocompletion.md b/docs/tutorial/options-autocompletion.md index 43777d04fb..fdfc875f7c 100644 --- a/docs/tutorial/options-autocompletion.md +++ b/docs/tutorial/options-autocompletion.md @@ -16,27 +16,7 @@ To check it quickly without creating a new Python package, use the `typer` comma Then let's create small example program: -//// tab | Python 3.7+ - -```Python -{!> ../docs_src/options_autocompletion/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python -{!> ../docs_src/options_autocompletion/tutorial001.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial001_an.py *} And let's try it with the `typer` command to get completion: @@ -70,27 +50,7 @@ Right now we get completion for the *CLI option* names, but not for the values. We can provide completion for the values creating an `autocompletion` function, similar to the `callback` functions from [CLI Option Callback and Context](./options/callback-and-context.md){.internal-link target=_blank}: -//// tab | Python 3.7+ - -```Python hl_lines="5-6 15" -{!> ../docs_src/options_autocompletion/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4-5 14" -{!> ../docs_src/options_autocompletion/tutorial002.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial002_an.py hl[5:6,15] *} We return a `list` of strings from the `complete_name()` function. @@ -119,27 +79,7 @@ Modify the `complete_name()` function to receive a parameter of type `str`, it w Then we can check and return only the values that start with the incomplete value from the command line: -//// tab | Python 3.7+ - -```Python hl_lines="7-12" -{!> ../docs_src/options_autocompletion/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6-11" -{!> ../docs_src/options_autocompletion/tutorial003.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial003_an.py hl[7:12] *} Now let's try it: @@ -178,27 +118,7 @@ In the `complete_name()` function, instead of providing one `str` per completion So, in the end, we return a `list` of `tuples` of `str`: -//// tab | Python 3.7+ - -```Python hl_lines="4-8 11-17" -{!> ../docs_src/options_autocompletion/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="3-7 10-16" -{!> ../docs_src/options_autocompletion/tutorial004.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial004_an.py hl[4:8,11:17] *} /// tip @@ -239,27 +159,7 @@ Instead of creating and returning a list with values (`str` or `tuple`), we can That way our function will be a generator that **Typer** (actually Click) can iterate: -//// tab | Python 3.7+ - -```Python hl_lines="11-14" -{!> ../docs_src/options_autocompletion/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="10-13" -{!> ../docs_src/options_autocompletion/tutorial005.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial005_an.py hl[11:14] *} That simplifies our code a bit and works the same. @@ -295,27 +195,7 @@ So, for now, take this as a sneak peek 😉. For this we use a `List` of `str`: -//// tab | Python 3.7+ - -```Python hl_lines="9-14" -{!> ../docs_src/options_autocompletion/tutorial006_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="8-11" -{!> ../docs_src/options_autocompletion/tutorial006.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial006_an.py hl[9:14] *} And then we can use it like: @@ -340,27 +220,7 @@ But you can access the context by declaring a function parameter of type `typer. And from that context you can get the current values for each parameter. -//// tab | Python 3.7+ - -```Python hl_lines="13-14 16" -{!> ../docs_src/options_autocompletion/tutorial007_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="12-13 15" -{!> ../docs_src/options_autocompletion/tutorial007.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial007_an.py hl[13:14,16] *} We are getting the `names` already provided with `--name` in the command line before this completion was triggered. @@ -436,27 +296,7 @@ You can print to "standard error" with a **Rich** `Console(stderr=True)`. Using `stderr=True` tells **Rich** that the output should be shown in "standard error". -//// tab | Python 3.7+ - -```Python hl_lines="13 16-17" -{!> ../docs_src/options_autocompletion/tutorial008_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="12 15-16" -{!> ../docs_src/options_autocompletion/tutorial008.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial008_an.py hl[13,16:17] *} /// info @@ -504,27 +344,7 @@ But it's probably useful only in very advanced use cases. Of course, you can declare everything if you need it, the context, the raw *CLI parameters*, and the incomplete `str`: -//// tab | Python 3.7+ - -```Python hl_lines="16" -{!> ../docs_src/options_autocompletion/tutorial009_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="15" -{!> ../docs_src/options_autocompletion/tutorial009.py!} -``` - -//// +{* docs_src/options_autocompletion/tutorial009_an.py hl[16] *} Check it: diff --git a/docs/tutorial/options/callback-and-context.md b/docs/tutorial/options/callback-and-context.md index 249616f072..9a6ebf9dca 100644 --- a/docs/tutorial/options/callback-and-context.md +++ b/docs/tutorial/options/callback-and-context.md @@ -8,27 +8,7 @@ In those cases you can use a *CLI parameter* callback function. For example, you could do some validation before the rest of the code is executed. -//// tab | Python 3.7+ - -```Python hl_lines="7-10 13" -{!> ../docs_src/options/callback/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6-9 12" -{!> ../docs_src/options/callback/tutorial001.py!} -``` - -//// +{* docs_src/options/callback/tutorial001_an.py hl[7:10,13] *} Here you pass a function to `typer.Option()` or `typer.Argument()` with the keyword argument `callback`. @@ -114,27 +94,7 @@ But the main **important point** is that it is all based on values printed by yo Let's say that when the callback is running, we want to show a message saying that it's validating the name: -//// tab | Python 3.7+ - -```Python hl_lines="8" -{!> ../docs_src/options/callback/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="7" -{!> ../docs_src/options/callback/tutorial002.py!} -``` - -//// +{* docs_src/options/callback/tutorial002_an.py hl[8] *} And because the callback will be called when the shell calls your program asking for completion, that message `"Validating name"` will be printed and it will break completion. @@ -169,27 +129,7 @@ But you can access the context by declaring a function parameter of type `typer. The "context" has some additional data about the current execution of your program: -//// tab | Python 3.7+ - -```Python hl_lines="7-9" -{!> ../docs_src/options/callback/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6-8" -{!> ../docs_src/options/callback/tutorial003.py!} -``` - -//// +{* docs_src/options/callback/tutorial003_an.py hl[7:9] *} The `ctx.resilient_parsing` will be `True` when handling completion, so you can just return without printing anything else. @@ -221,27 +161,7 @@ Hello Camila The same way you can access the `typer.Context` by declaring a function parameter with its value, you can declare another function parameter with type `typer.CallbackParam` to get the specific Click `Parameter` object. -//// tab | Python 3.7+ - -```Python hl_lines="7 10" -{!> ../docs_src/options/callback/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6 9" -{!> ../docs_src/options/callback/tutorial004.py!} -``` - -//// +{* docs_src/options/callback/tutorial004_an.py hl[7,10] *} It's probably not very common, but you could do it if you need it. diff --git a/docs/tutorial/options/help.md b/docs/tutorial/options/help.md index f2ee34db51..b0d389f875 100644 --- a/docs/tutorial/options/help.md +++ b/docs/tutorial/options/help.md @@ -4,27 +4,7 @@ You already saw how to add a help text for *CLI arguments* with the `help` param Let's now do the same for *CLI options*: -//// tab | Python 3.7+ - -```Python hl_lines="7-8" -{!> ../docs_src/options/help/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6-7" -{!> ../docs_src/options/help/tutorial001.py!} -``` - -//// +{* docs_src/options/help/tutorial001_an.py hl[7:8] *} The same way as with `typer.Argument()`, we can put `typer.Option()` inside of `Annotated`. @@ -76,27 +56,7 @@ The same as with *CLI arguments*, you can put the help for some *CLI options* in If you have installed Rich as described in the docs for [Printing and Colors](../printing.md){.internal-link target=_blank}, you can set the `rich_help_panel` parameter to the name of the panel you want for each *CLI option*: -//// tab | Python 3.7+ - -```Python hl_lines="11 17" -{!> ../docs_src/options/help/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="8 11" -{!> ../docs_src/options/help/tutorial002.py!} -``` - -//// +{* docs_src/options/help/tutorial002_an.py hl[11,17] *} Now, when you check the `--help` option, you will see a default panel named "`Options`" for the *CLI options* that don't have a custom `rich_help_panel`. @@ -142,27 +102,7 @@ If you are in a hurry you can jump there, but otherwise, it would be better to c You can tell Typer to not show the default value in the help text with `show_default=False`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/help/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/help/tutorial003.py!} -``` - -//// +{* docs_src/options/help/tutorial003_an.py hl[5] *} And it will no longer show the default value in the help text: @@ -199,27 +139,7 @@ In **Typer** these default values are shown by default. 👀 You can use the same `show_default` to pass a custom string (instead of a `bool`) to customize the default value to be shown in the help text: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/options/help/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6" -{!> ../docs_src/options/help/tutorial004.py!} -``` - -//// +{* docs_src/options/help/tutorial004_an.py hl[7] *} And it will be used in the help text: diff --git a/docs/tutorial/options/name.md b/docs/tutorial/options/name.md index a724a5b563..40e9f4687f 100644 --- a/docs/tutorial/options/name.md +++ b/docs/tutorial/options/name.md @@ -28,31 +28,7 @@ Let's say the function parameter name is `user_name` as above, but you want the You can pass the *CLI option* name that you want to have in the following positional argument passed to `typer.Option()`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/name/tutorial001_an.py!} -``` - -Here you are passing the string `"--name"` as the first positional argument to `typer.Option()`. - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/name/tutorial001.py!} -``` - -Here you are passing the string `"--name"` as the second positional argument to `typer.Option()`, as the first argument is `...` to mark it as required. - -//// +{* docs_src/options/name/tutorial001_an.py hl[5] *} /// info @@ -209,27 +185,7 @@ You can overwrite the *CLI option* name to use as in the previous example, but y For example, extending the previous example, let's add a *CLI option* short name `-n`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/name/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/name/tutorial002.py!} -``` - -//// +{* docs_src/options/name/tutorial002_an.py hl[5] *} Here we are overwriting the *CLI option* name that by default would be `--user-name`, and we are defining it to be `--name`. And we are also declaring a *CLI option* short name of `-n`. @@ -260,27 +216,7 @@ Hello Camila If you only declare a short name like `-n` then that will be the only *CLI option* name. And neither `--name` nor `--user-name` will be available. -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/name/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/name/tutorial003.py!} -``` - -//// +{* docs_src/options/name/tutorial003_an.py hl[5] *} Check it: @@ -308,27 +244,7 @@ Hello Camila Continuing with the example above, as **Typer** allows you to declare a *CLI option* as having only a short name, if you want to have the default long name plus a short name, you have to declare both explicitly: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/name/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/name/tutorial004.py!} -``` - -//// +{* docs_src/options/name/tutorial004_an.py hl[5] *} Check it: @@ -362,27 +278,7 @@ You can create multiple short names and use them together. You don't have to do anything special for it to work (apart from declaring those short versions): -//// tab | Python 3.7+ - -```Python hl_lines="6-7" -{!> ../docs_src/options/name/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5-6" -{!> ../docs_src/options/name/tutorial005.py!} -``` - -//// +{* docs_src/options/name/tutorial005_an.py hl[6:7] *} /// tip diff --git a/docs/tutorial/options/password.md b/docs/tutorial/options/password.md index 8601d848b6..d213d83cbe 100644 --- a/docs/tutorial/options/password.md +++ b/docs/tutorial/options/password.md @@ -2,27 +2,7 @@ Apart from having a prompt, you can make a *CLI option* have a `confirmation_prompt=True`: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/options/password/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5" -{!> ../docs_src/options/password/tutorial001.py!} -``` - -//// +{* docs_src/options/password/tutorial001_an.py hl[7] *} And the CLI program will ask for confirmation: @@ -50,27 +30,7 @@ You can achieve the same using `hide_input=True`. And if you combine it with `confirmation_prompt=True` you can easily receive a password with double confirmation: -//// tab | Python 3.7+ - -```Python hl_lines="8" -{!> ../docs_src/options/password/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6-8" -{!> ../docs_src/options/password/tutorial002.py!} -``` - -//// +{* docs_src/options/password/tutorial002_an.py hl[8] *} Check it: diff --git a/docs/tutorial/options/prompt.md b/docs/tutorial/options/prompt.md index e55a09551e..158934a2a2 100644 --- a/docs/tutorial/options/prompt.md +++ b/docs/tutorial/options/prompt.md @@ -2,27 +2,7 @@ It's also possible to, instead of just showing an error, ask for the missing value with `prompt=True`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/prompt/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/prompt/tutorial001.py!} -``` - -//// +{* docs_src/options/prompt/tutorial001_an.py hl[5] *} And then your program will ask the user for it in the terminal: @@ -44,27 +24,7 @@ Hello Camila Gutiérrez You can also set a custom prompt, passing the string that you want to use instead of just `True`: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/options/prompt/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5" -{!> ../docs_src/options/prompt/tutorial002.py!} -``` - -//// +{* docs_src/options/prompt/tutorial002_an.py hl[7] *} And then your program will ask for it using with your custom prompt: @@ -90,27 +50,7 @@ You can do it passing the parameter `confirmation_prompt=True`. Let's say it's a CLI app to delete a project: -//// tab | Python 3.7+ - -```Python hl_lines="6" -{!> ../docs_src/options/prompt/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/options/prompt/tutorial003.py!} -``` - -//// +{* docs_src/options/prompt/tutorial003_an.py hl[6] *} And it will prompt the user for a value and then for the confirmation: diff --git a/docs/tutorial/options/required.md b/docs/tutorial/options/required.md index 4b2c2226eb..06c12844b1 100644 --- a/docs/tutorial/options/required.md +++ b/docs/tutorial/options/required.md @@ -13,33 +13,15 @@ To make a *CLI option* required, you can put `typer.Option()` inside of `Annotat Let's make `--lastname` a required *CLI option*: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/options/required/tutorial001_an.py!} -``` - -//// +{* docs_src/options/required/tutorial001_an.py hl[5] *} The same way as with `typer.Argument()`, the old style of using the function parameter default value is also supported, in that case you would just not pass anything to the `default` parameter. -//// tab | Python 3.7+ non-Annotated - -```Python hl_lines="4" -{!> ../docs_src/options/required/tutorial001.py!} -``` - -//// +{* docs_src/options/required/tutorial001.py hl[4] *} Or you can explictily pass `...` to `typer.Option(default=...)`: -//// tab | Python 3.7+ non-Annotated - -```Python hl_lines="4" -{!> ../docs_src/options/required/tutorial002.py!} -``` - -//// +{* docs_src/options/required/tutorial002.py hl[4] *} /// info diff --git a/docs/tutorial/options/version.md b/docs/tutorial/options/version.md index f76112ce39..23daec284d 100644 --- a/docs/tutorial/options/version.md +++ b/docs/tutorial/options/version.md @@ -8,27 +8,7 @@ It would show the version of your CLI program and then it would terminate it. Ev Let's see a first version of how it could look like: -//// tab | Python 3.7+ - -```Python hl_lines="9-12 17-19" -{!> ../docs_src/options/version/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="8-11 16-18" -{!> ../docs_src/options/version/tutorial001.py!} -``` - -//// +{* docs_src/options/version/tutorial001_an.py hl[9:12,17:19] *} /// tip @@ -77,27 +57,7 @@ Awesome CLI Version: 0.1.0 But now let's say that the `--name` *CLI option* that we declared before `--version` is required, and it has a callback that could exit the program: -//// tab | Python 3.7+ - -```Python hl_lines="15-17 22-24" -{!> ../docs_src/options/version/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="14-16 21-23" -{!> ../docs_src/options/version/tutorial002.py!} -``` - -//// +{* docs_src/options/version/tutorial002_an.py hl[15:17,22:24] *} Then our CLI program could not work as expected in some cases as it is *right now*, because if we use `--version` after `--name` then the callback for `--name` will be processed before and we can get its error: @@ -136,27 +96,7 @@ For those cases, we can mark a *CLI parameter* (a *CLI option* or *CLI argument* That will tell **Typer** (actually Click) that it should process this *CLI parameter* before the others: -//// tab | Python 3.7+ - -```Python hl_lines="23-26" -{!> ../docs_src/options/version/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="22-24" -{!> ../docs_src/options/version/tutorial003.py!} -``` - -//// +{* docs_src/options/version/tutorial003_an.py hl[23:26] *} Check it: diff --git a/docs/tutorial/parameter-types/bool.md b/docs/tutorial/parameter-types/bool.md index 14adc6a6dd..3d0d80cc63 100644 --- a/docs/tutorial/parameter-types/bool.md +++ b/docs/tutorial/parameter-types/bool.md @@ -10,27 +10,7 @@ Let's say that we want a `--force` *CLI option* only, we want to discard `--no-f We can do that by specifying the exact name we want: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/bool/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/bool/tutorial001.py!} -``` - -//// +{* docs_src/parameter_types/bool/tutorial001_an.py hl[5] *} Now there's only a `--force` *CLI option*: @@ -78,27 +58,7 @@ We might want to instead have `--accept` and `--reject`. We can do that by passing a single `str` with the 2 names for the `bool` *CLI option* separated by `/`: -//// tab | Python 3.7+ - -```Python hl_lines="7" -{!> ../docs_src/parameter_types/bool/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="6" -{!> ../docs_src/parameter_types/bool/tutorial002.py!} -``` - -//// +{* docs_src/parameter_types/bool/tutorial002_an.py hl[7] *} Check it: @@ -139,27 +99,7 @@ The same way, you can declare short versions of the names for these *CLI options For example, let's say we want `-f` for `--force` and `-F` for `--no-force`: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/bool/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/bool/tutorial003.py!} -``` - -//// +{* docs_src/parameter_types/bool/tutorial003_an.py hl[5] *} Check it: @@ -195,27 +135,7 @@ If you want to (although it might not be a good idea), you can declare only *CLI To do that, use a space and a single `/` and pass the negative name after: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/bool/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/bool/tutorial004.py!} -``` - -//// +{* docs_src/parameter_types/bool/tutorial004_an.py hl[5] *} /// tip diff --git a/docs/tutorial/parameter-types/custom-types.md b/docs/tutorial/parameter-types/custom-types.md index b048c85bc9..79da55878d 100644 --- a/docs/tutorial/parameter-types/custom-types.md +++ b/docs/tutorial/parameter-types/custom-types.md @@ -13,27 +13,7 @@ There are two ways to achieve this: `typer.Argument` and `typer.Option` can create custom parameter types with a `parser` callable. -//// tab | Python 3.7+ - -```Python hl_lines="13-14 18-19" -{!> ../docs_src/parameter_types/custom_types/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="12-13 17-18" -{!> ../docs_src/parameter_types/custom_types/tutorial001.py!} -``` - -//// +{* docs_src/parameter_types/custom_types/tutorial001_an.py hl[13:14,18:19] *} The function (or callable) that you pass to the parameter `parser` will receive the input value as a string and should return the parsed value with your own custom type. @@ -41,10 +21,4 @@ The function (or callable) that you pass to the parameter `parser` will receive If you already have a Click Custom Type, you can use it in `typer.Argument()` and `typer.Option()` with the `click_type` parameter. -//// tab | Python 3.7+ - -```Python hl_lines="14-18 22-25" -{!> ../docs_src/parameter_types/custom_types/tutorial002_an.py!} -``` - -//// +{* docs_src/parameter_types/custom_types/tutorial002_an.py hl[14:18,22:25] *} diff --git a/docs/tutorial/parameter-types/datetime.md b/docs/tutorial/parameter-types/datetime.md index 84f3524eee..3df6f0f7e8 100644 --- a/docs/tutorial/parameter-types/datetime.md +++ b/docs/tutorial/parameter-types/datetime.md @@ -4,9 +4,7 @@ You can specify a *CLI parameter* as a Python ../docs_src/parameter_types/datetime/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="8" -{!> ../docs_src/parameter_types/datetime/tutorial002.py!} -``` - -//// +{* docs_src/parameter_types/datetime/tutorial002_an.py hl[11] *} /// tip diff --git a/docs/tutorial/parameter-types/enum.md b/docs/tutorial/parameter-types/enum.md index 288eee5a92..60852faf54 100644 --- a/docs/tutorial/parameter-types/enum.md +++ b/docs/tutorial/parameter-types/enum.md @@ -2,9 +2,7 @@ To define a *CLI parameter* that can take a value from a predefined set of values you can use a standard Python `enum.Enum`: -```Python hl_lines="1 6 7 8 9 12 13" -{!../docs_src/parameter_types/enum/tutorial001.py!} -``` +{* docs_src/parameter_types/enum/tutorial001.py hl[1,6,7,8,9,12,13] *} /// tip @@ -56,27 +54,7 @@ Error: Invalid value for '--network': 'CONV' is not one of 'simple', 'conv', 'ls You can make an `Enum` (choice) *CLI parameter* be case-insensitive with the `case_sensitive` parameter: -//// tab | Python 3.7+ - -```Python hl_lines="15" -{!> ../docs_src/parameter_types/enum/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="13" -{!> ../docs_src/parameter_types/enum/tutorial002.py!} -``` - -//// +{* docs_src/parameter_types/enum/tutorial002_an.py hl[15] *} And then the values of the `Enum` will be checked no matter if lower case, upper case, or a mix: @@ -100,27 +78,7 @@ Training neural network of type: lstm A *CLI parameter* can also take a list of `Enum` values: -//// tab | Python 3.7+ - -```Python hl_lines="14" -{!> ../docs_src/parameter_types/enum/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="13" -{!> ../docs_src/parameter_types/enum/tutorial003.py!} -``` - -//// +{* docs_src/parameter_types/enum/tutorial003_an.py hl[14] *} This works just like any other parameter value taking a list of things: diff --git a/docs/tutorial/parameter-types/file.md b/docs/tutorial/parameter-types/file.md index 274962cf07..391c7f8f09 100644 --- a/docs/tutorial/parameter-types/file.md +++ b/docs/tutorial/parameter-types/file.md @@ -47,27 +47,7 @@ content = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o" You will get all the correct editor support, attributes, methods, etc for the file-like object:` -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/file/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/file/tutorial001.py!} -``` - -//// +{* docs_src/parameter_types/file/tutorial001_an.py hl[5] *} Check it: @@ -94,27 +74,7 @@ Config line: some more settings For writing text, you can use `typer.FileTextWrite`: -//// tab | Python 3.7+ - -```Python hl_lines="5-6" -{!> ../docs_src/parameter_types/file/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4-5" -{!> ../docs_src/parameter_types/file/tutorial002.py!} -``` - -//// +{* docs_src/parameter_types/file/tutorial002_an.py hl[5:6] *} This would be for writing human text, like: @@ -158,27 +118,7 @@ You will receive `bytes` from it. It's useful for reading binary files like images: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/file/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/file/tutorial003.py!} -``` - -//// +{* docs_src/parameter_types/file/tutorial003_an.py hl[5] *} Check it: @@ -207,27 +147,7 @@ Have in mind that you have to pass `bytes` to its `.write()` method, not `str`. If you have a `str`, you have to encode it first to get `bytes`. -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/file/tutorial004_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/file/tutorial004.py!} -``` - -//// +{* docs_src/parameter_types/file/tutorial004_an.py hl[5] *}
@@ -277,27 +197,7 @@ You can override the `mode` from the defaults above. For example, you could use `mode="a"` to write "appending" to the same file: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/file/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/file/tutorial005.py!} -``` - -//// +{* docs_src/parameter_types/file/tutorial005_an.py hl[5] *} /// tip diff --git a/docs/tutorial/parameter-types/index.md b/docs/tutorial/parameter-types/index.md index f7889944f0..8de90c62e0 100644 --- a/docs/tutorial/parameter-types/index.md +++ b/docs/tutorial/parameter-types/index.md @@ -8,9 +8,7 @@ When you declare a *CLI parameter* with some type **Typer** will convert the dat For example: -```Python hl_lines="4" -{!../docs_src/parameter_types/index/tutorial001.py!} -``` +{* docs_src/parameter_types/index/tutorial001.py hl[4] *} In this example, the value received for the *CLI argument* `NAME` will be treated as `str`. diff --git a/docs/tutorial/parameter-types/number.md b/docs/tutorial/parameter-types/number.md index 062fa7bce3..914f58a035 100644 --- a/docs/tutorial/parameter-types/number.md +++ b/docs/tutorial/parameter-types/number.md @@ -2,27 +2,7 @@ You can define numeric validations with `max` and `min` values for `int` and `float` *CLI parameters*: -//// tab | Python 3.7+ - -```Python hl_lines="6-8" -{!> ../docs_src/parameter_types/number/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5-7" -{!> ../docs_src/parameter_types/number/tutorial001.py!} -``` - -//// +{* docs_src/parameter_types/number/tutorial001_an.py hl[6:8] *} *CLI arguments* and *CLI options* can both use these validations. @@ -93,27 +73,7 @@ You might want to, instead of showing an error, use the closest minimum or maxim You can do it with the `clamp` parameter: -//// tab | Python 3.7+ - -```Python hl_lines="6-8" -{!> ../docs_src/parameter_types/number/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5-7" -{!> ../docs_src/parameter_types/number/tutorial002.py!} -``` - -//// +{* docs_src/parameter_types/number/tutorial002_an.py hl[6:8] *} And then, when you pass data that is out of the valid range, it will be "clamped", the closest valid value will be used: @@ -142,27 +102,7 @@ ID is 5 You can make a *CLI option* work as a counter with the `counter` parameter: -//// tab | Python 3.7+ - -```Python hl_lines="5" -{!> ../docs_src/parameter_types/number/tutorial003_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4" -{!> ../docs_src/parameter_types/number/tutorial003.py!} -``` - -//// +{* docs_src/parameter_types/number/tutorial003_an.py hl[5] *} It means that the *CLI option* will be like a boolean flag, e.g. `--verbose`. diff --git a/docs/tutorial/parameter-types/path.md b/docs/tutorial/parameter-types/path.md index 0268630bcd..4c715b8acd 100644 --- a/docs/tutorial/parameter-types/path.md +++ b/docs/tutorial/parameter-types/path.md @@ -4,27 +4,7 @@ You can declare a *CLI parameter* to be a standard Python ../docs_src/parameter_types/path/tutorial001_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="1 7" -{!> ../docs_src/parameter_types/path/tutorial001.py!} -``` - -//// +{* docs_src/parameter_types/path/tutorial001_an.py hl[1,8] *} And again, as you receive a standard Python `Path` object the same as the type annotation, your editor will give you autocompletion for all its attributes and methods. @@ -85,27 +65,7 @@ All these parameters come directly from ../docs_src/parameter_types/path/tutorial002_an.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="9-14" -{!> ../docs_src/parameter_types/path/tutorial002.py!} -``` - -//// +{* docs_src/parameter_types/path/tutorial002_an.py hl[11:16] *} Check it: diff --git a/docs/tutorial/parameter-types/uuid.md b/docs/tutorial/parameter-types/uuid.md index afe5986377..906ca618e3 100644 --- a/docs/tutorial/parameter-types/uuid.md +++ b/docs/tutorial/parameter-types/uuid.md @@ -22,9 +22,7 @@ This wouldn't be true if you just used `int`s as identifiers, as most databases You can declare a *CLI parameter* as a UUID: -```Python hl_lines="1 6 7 8" -{!../docs_src/parameter_types/uuid/tutorial001.py!} -``` +{* docs_src/parameter_types/uuid/tutorial001.py hl[1,6,7,8] *} Your Python code will receive a standard Python `UUID` object with all its attributes and methods, and as you are annotating your function parameter with that type, you will have type checks, autocompletion in your editor, etc. diff --git a/docs/tutorial/printing.md b/docs/tutorial/printing.md index 75150d329d..1a5bd4e176 100644 --- a/docs/tutorial/printing.md +++ b/docs/tutorial/printing.md @@ -2,9 +2,7 @@ You can use the normal `print()` to show information on the screen: -```Python hl_lines="5" -{!../docs_src/first_steps/tutorial001.py!} -``` +{* docs_src/first_steps/tutorial001.py hl[5] *} It will show the output normally: @@ -26,9 +24,7 @@ You can also display beautiful and more complex information using custom markup syntax to set colors and styles, for example: -```Python hl_lines="6" -{!../docs_src/printing/tutorial002.py!} -``` +{* docs_src/printing/tutorial002.py hl[6] *}
@@ -82,9 +76,7 @@ When you call Rich's `print`, it automatically creates this object and uses it. But for advanced use cases, you could create a `Console` yourself. -```Python hl_lines="2-3 5 9-12" -{!../docs_src/printing/tutorial003.py!} -``` +{* docs_src/printing/tutorial003.py hl[2:3,5,9:12] *} In this example, we create a `Console`, and a `Table`. And then we can add some rows to the table, and print it. @@ -160,9 +152,7 @@ You can print to "standard error" creating a Rich `Console` with `stderr=True`. Using `stderr=True` tells **Rich** that the output should be shown in "standard error". -```Python hl_lines="4 8" -{!../docs_src/printing/tutorial004.py!} -``` +{* docs_src/printing/tutorial004.py hl[4,8] *} When you try it in the terminal, it will probably just look the same: @@ -238,9 +228,7 @@ Again, you are much better off using Rich's Progress Display to show a progress bar, for example: -```Python hl_lines="4 9" -{!../docs_src/progressbar/tutorial001.py!} -``` +{* docs_src/progressbar/tutorial001.py hl[4,9] *} You put the thing that you want to iterate over inside of Rich's `track()`, and then iterate over that. @@ -48,9 +46,7 @@ Rich allows you to display many things in complex and advanced ways. For example, this will show two spinners: -```Python hl_lines="4 8-15" -{!../docs_src/progressbar/tutorial002.py!} -``` +{* docs_src/progressbar/tutorial002.py hl[4,8:15] *} I can't show you the beautiful animation here in the docs. 😅 @@ -104,9 +100,7 @@ with typer.progressbar(something) as progress: And you pass as function argument to `typer.progressbar()` the thing that you would normally iterate over. -```Python hl_lines="8" -{!../docs_src/progressbar/tutorial003.py!} -``` +{* docs_src/progressbar/tutorial003.py hl[8] *} So, if you have a list of users, this could be: @@ -169,9 +163,7 @@ The progress bar is generated from the length of the iterable (e.g. the list of But if the length is not available (for example, with something that fetches a new user from a web API each time) you can pass an explicit `length` to `typer.progressbar()`. -```Python hl_lines="14" -{!../docs_src/progressbar/tutorial004.py!} -``` +{* docs_src/progressbar/tutorial004.py hl[14] *} Check it: @@ -219,9 +211,7 @@ Remember, you are much better off using @@ -83,9 +77,7 @@ Aborted! If you installed Rich as described in [Printing and Colors](printing.md){.internal-link target=_blank}, you can use Rich to prompt the user for input: -```Python hl_lines="2 6" -{!../docs_src/prompt/tutorial004.py!} -``` +{* docs_src/prompt/tutorial004.py hl[2,6] *} And when you run it, it will look like: diff --git a/docs/tutorial/subcommands/add-typer.md b/docs/tutorial/subcommands/add-typer.md index 55439acf29..82dbc876e3 100644 --- a/docs/tutorial/subcommands/add-typer.md +++ b/docs/tutorial/subcommands/add-typer.md @@ -10,9 +10,7 @@ Let's imagine that you are creating a *CLI program* to manage items in some dist It could be in an `items.py` file with this: -```Python -{!../docs_src/subcommands/tutorial001/items.py!} -``` +{* docs_src/subcommands/tutorial001/items.py *} And you would use it like: @@ -32,9 +30,7 @@ But then you realize that you also have to manage users from your *CLI app*. It could be a file `users.py` with something like: -```Python -{!../docs_src/subcommands/tutorial001/users.py!} -``` +{* docs_src/subcommands/tutorial001/users.py *} And you would use it like: @@ -58,9 +54,7 @@ In this case, as with `git remote`, we can put them together as subcommands in a Now create a `main.py` with: -```Python hl_lines="3 4 7 8" -{!../docs_src/subcommands/tutorial001/main.py!} -``` +{* docs_src/subcommands/tutorial001/main.py hl[3,4,7,8] *} Here's what we do in `main.py`: diff --git a/docs/tutorial/subcommands/callback-override.md b/docs/tutorial/subcommands/callback-override.md index fa82d4ee3b..b99232c543 100644 --- a/docs/tutorial/subcommands/callback-override.md +++ b/docs/tutorial/subcommands/callback-override.md @@ -6,9 +6,7 @@ When adding a Typer app inside of another, the sub-Typer can also have its own c It can handle any *CLI parameters* that go before its own commands and execute any extra code: -```Python hl_lines="9 10 11" -{!../docs_src/subcommands/callback_override/tutorial001.py!} -``` +{* docs_src/subcommands/callback_override/tutorial001.py hl[9,10,11] *} In this case it doesn't define any *CLI parameters*, it just writes a message. @@ -30,9 +28,7 @@ Creating user: Camila It's also possible to add a callback when creating the `typer.Typer()` app that will be added to another Typer app: -```Python hl_lines="6 7 10" -{!../docs_src/subcommands/callback_override/tutorial002.py!} -``` +{* docs_src/subcommands/callback_override/tutorial002.py hl[6,7,10] *} This achieves exactly the same as above, it's just another place to add the callback. @@ -55,9 +51,7 @@ If a callback was added when creating the `typer.Typer()` app, it's possible to This is the same information you saw on the section about [Commands - Typer Callback](../commands/callback.md){.internal-link target=_blank}, and it applies the same for sub-Typer apps: -```Python hl_lines="6 7 10 14 15 16" -{!../docs_src/subcommands/callback_override/tutorial003.py!} -``` +{* docs_src/subcommands/callback_override/tutorial003.py hl[6,7,10,14,15,16] *} Here we had defined a callback when creating the `typer.Typer()` sub-app, but then we override it with a new callback with the function `user_callback()`. @@ -83,9 +77,7 @@ Lastly, you can override the callback defined anywhere else when adding a sub-Ty This has the highest priority: -```Python hl_lines="13 14 17" -{!../docs_src/subcommands/callback_override/tutorial004.py!} -``` +{* docs_src/subcommands/callback_override/tutorial004.py hl[13,14,17] *} Notice that the precedence goes to `app.add_typer()` and is not affected by the order of execution. There's another callback defined below, but the one from `app.add_typer()` wins. diff --git a/docs/tutorial/subcommands/name-and-help.md b/docs/tutorial/subcommands/name-and-help.md index e6d96caa54..47eced3dd3 100644 --- a/docs/tutorial/subcommands/name-and-help.md +++ b/docs/tutorial/subcommands/name-and-help.md @@ -12,9 +12,7 @@ app.add_typer(users.app, name="users") We can also set the `help` while adding a Typer: -```Python hl_lines="6" -{!../docs_src/subcommands/name_help/tutorial001.py!} -``` +{* docs_src/subcommands/name_help/tutorial001.py hl[6] *} And then we get that help text for that command in the *CLI program*: @@ -91,9 +89,7 @@ And if that Typer app is added to another Typer app, the default name of the com Here's an example: -```Python hl_lines="6 9 10 11 12 13" -{!../docs_src/subcommands/name_help/tutorial002.py!} -``` +{* docs_src/subcommands/name_help/tutorial002.py hl[6,9,10,11,12,13] *} Notice that now we added the sub-Typer without specifying a `name` nor a `help`. @@ -147,9 +143,7 @@ This has the lowest priority, we'll see later what has a higher priority and can Check the code: -```Python hl_lines="6 7 8 9 12" -{!../docs_src/subcommands/name_help/tutorial003.py!} -``` +{* docs_src/subcommands/name_help/tutorial003.py hl[6,7,8,9,12] *} This achieves exactly the same as the previous example. @@ -193,9 +187,7 @@ Commands: The same as with normal **Typer** apps, if you pass a `callback` to `typer.Typer(callback=some_function)` and then override it with `@app.callback()`, the name and help text will be inferred from the new callback: -```Python hl_lines="16 17 18 19 20" -{!../docs_src/subcommands/name_help/tutorial004.py!} -``` +{* docs_src/subcommands/name_help/tutorial004.py hl[16,17,18,19,20] *} Now the name of the command will be `users` instead of `old-callback`, and the help text will be `Manage users in the app.` instead of `Old callback help.`. @@ -243,9 +235,7 @@ This takes precedence over inferring the name and help from a callback set in `@ Check the code: -```Python hl_lines="15 16 17 18 21" -{!../docs_src/subcommands/name_help/tutorial005.py!} -``` +{* docs_src/subcommands/name_help/tutorial005.py hl[15,16,17,18,21] *} Now the command will be `new-users` instead of `users`. And the help text will be `I have the highland! Create some users.` instead of the previous ones. @@ -315,9 +305,7 @@ If you set it explicitly, that takes precedence over inferring. You can set it when creating a new `typer.Typer()`: -```Python hl_lines="12" -{!../docs_src/subcommands/name_help/tutorial006.py!} -``` +{* docs_src/subcommands/name_help/tutorial006.py hl[12] *} /// info @@ -371,9 +359,7 @@ Any parameter that you use when creating a `typer.Typer()` app can be overridden Continuing with the previous example, we now override the values in `@user_app.callback()`: -```Python hl_lines="24" -{!../docs_src/subcommands/name_help/tutorial007.py!} -``` +{* docs_src/subcommands/name_help/tutorial007.py hl[24] *} And now the command name will be `call-users` and the help text will be `Help from callback for users.`. @@ -417,9 +403,7 @@ Commands: And finally, with the highest priority, you can override all that by explicitly setting the `name` and `help` in `app.add_typer()`, just like we did on the first example above: -```Python hl_lines="21" -{!../docs_src/subcommands/name_help/tutorial008.py!} -``` +{* docs_src/subcommands/name_help/tutorial008.py hl[21] *} And now, with the highest priorities of them all, the command name will now be `cake-sith-users` and the help text will be `Unlimited powder! Eh, users.`. diff --git a/docs/tutorial/subcommands/nested-subcommands.md b/docs/tutorial/subcommands/nested-subcommands.md index c991faa9da..d56028b3ee 100644 --- a/docs/tutorial/subcommands/nested-subcommands.md +++ b/docs/tutorial/subcommands/nested-subcommands.md @@ -12,9 +12,7 @@ And each of those could have their own commands, like `create` and `delete`. Let's start with a file `reigns.py`: -```Python -{!../docs_src/subcommands/tutorial003/reigns.py!} -``` +{* docs_src/subcommands/tutorial003/reigns.py *} This is already a simple *CLI program* to manage reigns: @@ -51,9 +49,7 @@ Destroying reign: Mordor And now the equivalent for managing towns in `towns.py`: -```Python -{!../docs_src/subcommands/tutorial003/towns.py!} -``` +{* docs_src/subcommands/tutorial003/towns.py *} With it, you can manage towns: @@ -90,9 +86,7 @@ Burning town: Vizima Now let's put the `reigns` and `towns` together in the same *CLI program* in `lands.py`: -```Python -{!../docs_src/subcommands/tutorial003/lands.py!} -``` +{* docs_src/subcommands/tutorial003/lands.py *} And now we have a single *CLI program* with a command (or command group) `reigns` that has its own commands. And another command `towns` with its own subcommands. @@ -193,9 +187,7 @@ This already is a quite deeply nested "tree" of commands/command groups. But to achieve that, we just have to add the `lands` **Typer** app to the same `main.py` file we already had: -```Python hl_lines="4 10" -{!../docs_src/subcommands/tutorial003/main.py!} -``` +{* docs_src/subcommands/tutorial003/main.py hl[4,10] *} And now we have everything in a single *CLI program*: @@ -246,39 +238,27 @@ Here are all the files if you want to review/copy them: `reigns.py`: -```Python -{!../docs_src/subcommands/tutorial003/reigns.py!} -``` +{* docs_src/subcommands/tutorial003/reigns.py *} `towns.py`: -```Python -{!../docs_src/subcommands/tutorial003/towns.py!} -``` +{* docs_src/subcommands/tutorial003/towns.py *} `lands.py`: -```Python -{!../docs_src/subcommands/tutorial003/lands.py!} -``` +{* docs_src/subcommands/tutorial003/lands.py *} `users.py`: -```Python -{!../docs_src/subcommands/tutorial003/users.py!} -``` +{* docs_src/subcommands/tutorial003/users.py *} `items.py`: -```Python -{!../docs_src/subcommands/tutorial003/items.py!} -``` +{* docs_src/subcommands/tutorial003/items.py *} `main.py`: -```Python -{!../docs_src/subcommands/tutorial003/main.py!} -``` +{* docs_src/subcommands/tutorial003/main.py *} /// tip diff --git a/docs/tutorial/subcommands/single-file.md b/docs/tutorial/subcommands/single-file.md index 50645267cd..f7e943ecc0 100644 --- a/docs/tutorial/subcommands/single-file.md +++ b/docs/tutorial/subcommands/single-file.md @@ -4,9 +4,7 @@ In some cases, it's possible that your application code needs to live on a singl You can still use the same ideas: -```Python -{!../docs_src/subcommands/tutorial002/main.py!} -``` +{* docs_src/subcommands/tutorial002/main.py *} There are several things to notice here... @@ -16,9 +14,7 @@ First, you can create `typer.Typer()` objects and add them to another one at the It doesn't have to be done after creating the subcommands: -```Python hl_lines="4 5 6 7" -{!../docs_src/subcommands/tutorial002/main.py!} -``` +{* docs_src/subcommands/tutorial002/main.py hl[4,5,6,7] *} You can add the commands (subcommands) to each `typer.Typer()` app later and it will still work. @@ -28,9 +24,7 @@ As you now have subcommands like `create` for `users` and for `items`, you can n So we use longer names: -```Python hl_lines="11 16 21 26 31" -{!../docs_src/subcommands/tutorial002/main.py!} -``` +{* docs_src/subcommands/tutorial002/main.py hl[11,16,21,26,31] *} ## Command name @@ -62,9 +56,7 @@ $ python main.py items items-create So we pass the name we want to use for each subcommand as the function argument to the decorator: -```Python hl_lines="10 15 20 25 30" -{!../docs_src/subcommands/tutorial002/main.py!} -``` +{* docs_src/subcommands/tutorial002/main.py hl[10,15,20,25,30] *} ## Check it diff --git a/docs/tutorial/terminating.md b/docs/tutorial/terminating.md index a8d0b49fa3..23343a651a 100644 --- a/docs/tutorial/terminating.md +++ b/docs/tutorial/terminating.md @@ -12,9 +12,7 @@ This doesn't have to mean that there's an error, just that nothing else needs to In that case, you can raise a `typer.Exit()` exception: -```Python hl_lines="9" -{!../docs_src/terminating/tutorial001.py!} -``` +{* docs_src/terminating/tutorial001.py hl[9] *} There are several things to see in this example. @@ -58,9 +56,7 @@ But then **Typer** (actually Click) catches it and just terminates the program n You can pass a `code` with a number other than `0` to tell the terminal that there was an error in the execution of the program: -```Python hl_lines="7" -{!../docs_src/terminating/tutorial002.py!} -``` +{* docs_src/terminating/tutorial002.py hl[7] *} Check it: @@ -103,9 +99,7 @@ There's a special exception that you can use to "abort" a program. It works more or less the same as `typer.Exit()` but will print `"Aborted!"` to the screen and can be useful in certain cases later to make it explicit that the execution was aborted: -```Python hl_lines="7" -{!../docs_src/terminating/tutorial003.py!} -``` +{* docs_src/terminating/tutorial003.py hl[7] *} Check it: diff --git a/docs/tutorial/testing.md b/docs/tutorial/testing.md index 2fc7e54f09..8e0f82ad7b 100644 --- a/docs/tutorial/testing.md +++ b/docs/tutorial/testing.md @@ -4,9 +4,7 @@ Testing **Typer** applications is very easy with . If you have a CLI with prompts, like: -//// tab | Python 3.7+ - -```Python hl_lines="8" -{!> ../docs_src/testing/app02_an/main.py!} -``` - -//// - -//// tab | Python 3.7+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="7" -{!> ../docs_src/testing/app02/main.py!} -``` - -//// +{* docs_src/testing/app02_an/main.py hl[8] *} That you would use like: @@ -167,23 +139,17 @@ When you hit the ENTER key after typing the email, that is just a "ne So, if you use `input="camila@example.com\n"` it means: "type `camila@example.com` in the terminal, then hit the ENTER key": -```Python hl_lines="9" -{!../docs_src/testing/app02/test_main.py!} -``` +{* docs_src/testing/app02/test_main.py hl[9] *} ## Test a function If you have a script and you never created an explicit `typer.Typer` app, like: -```Python hl_lines="9" -{!../docs_src/testing/app03/main.py!} -``` +{* docs_src/testing/app03/main.py hl[9] *} ...you can still test it, by creating an app during testing: -```Python hl_lines="6 7 13" -{!../docs_src/testing/app03/test_main.py!} -``` +{* docs_src/testing/app03/test_main.py hl[6,7,13] *} Of course, if you are testing that script, it's probably easier/cleaner to just create the explicit `typer.Typer` app in `main.py` instead of creating it just during the test. diff --git a/docs/tutorial/typer-command.md b/docs/tutorial/typer-command.md index 004415a6ae..803b44d0f5 100644 --- a/docs/tutorial/typer-command.md +++ b/docs/tutorial/typer-command.md @@ -241,9 +241,7 @@ You can also use the `typer` command to generate Markdown documentation for your For example, you could have a script like: -```Python -{!../docs_src/commands/help/tutorial001.py!} -``` +{* docs_src/commands/help/tutorial001.py *} ### Generate docs with the `typer` command diff --git a/docs/tutorial/using-click.md b/docs/tutorial/using-click.md index 950531ff7f..49517ffd73 100644 --- a/docs/tutorial/using-click.md +++ b/docs/tutorial/using-click.md @@ -28,9 +28,7 @@ A `Command` can have its own *CLI arguments* and *CLI options*, and it has a fun For example, in this Click app: -```Python hl_lines="7 14" -{!../docs_src/using_click/tutorial001.py!} -``` +{* docs_src/using_click/tutorial001.py hl[7,14] *} The original `hello` variable is converted by Click from a function to a `Command` object. And the original `hello` function is used by that `Command` internally, but it is no longer named `hello` (as `hello` is now a Click `Command`). @@ -46,9 +44,7 @@ And a `Group` can also have a function that it calls, right before calling the f For example: -```Python hl_lines="5 19 20" -{!../docs_src/using_click/tutorial002.py!} -``` +{* docs_src/using_click/tutorial002.py hl[5,19,20] *} The `cli` variable is converted by Click from a function to a `Group` object. And the original `cli` function is used by that `Group` internally. @@ -90,9 +86,7 @@ You can use it directly, and use the Click object with other Click applications. For example, you could have a **Typer** app, generate a Click `Group` from it, and then include other Click apps in it: -```Python hl_lines="15 16 29 31 34" -{!../docs_src/using_click/tutorial003.py!} -``` +{* docs_src/using_click/tutorial003.py hl[15,16,29,31,34] *} Notice that we add a callback that does nothing (only document the CLI program), to make sure **Typer** creates a Click `Group`. That way we can add sub-commands to that Click `Group`. @@ -136,9 +130,7 @@ Hello Camila! The same way, you can do the contrary and include a **Typer** sub app in a bigger Click app: -```Python hl_lines="31 33 36" -{!../docs_src/using_click/tutorial004.py!} -``` +{* docs_src/using_click/tutorial004.py hl[31,33,36] *} Notice that we don't have to add a callback or more commands, we can just create a **Typer** app that generates a single Click `Command`, as we don't need to include anything under the Typer app. diff --git a/mkdocs.yml b/mkdocs.yml index ead95508a0..042d7ad116 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -192,7 +192,7 @@ markdown_extensions: # Other extensions mdx_include: - base_path: docs + markdown_include_variants: extra: analytics: diff --git a/requirements-docs.txt b/requirements-docs.txt index 7bc027ac71..4f2c9b2f7b 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -16,3 +16,4 @@ cairosvg==2.7.1 # For griffe, it formats with black # black==24.3.0 mkdocs-macros-plugin==1.3.7 +markdown-include-variants==0.0.3 From 77a7216818c3b37128e4e85cf60f6af87e7e0bd4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 18 Nov 2024 22:24:26 +0000 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 2bfe701315..0d1fc2304e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,6 +13,10 @@ * 🐛 Fix printing HTML from Rich output. PR [#1055](/~https://github.com/fastapi/typer/pull/1055) by [@tiangolo](/~https://github.com/tiangolo). +### Docs + +* 📝 Update markdown includes to use the new simpler format. PR [#1054](/~https://github.com/fastapi/typer/pull/1054) by [@tiangolo](/~https://github.com/tiangolo). + ### Internal * ⬆ Bump ruff from 0.7.3 to 0.7.4. PR [#1051](/~https://github.com/fastapi/typer/pull/1051) by [@dependabot[bot]](/~https://github.com/apps/dependabot). From 53e21fdc09fe2ef2310a7e4a7e353f42712d5770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 18 Nov 2024 23:37:25 +0100 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.13.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 2 ++ typer/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 0d1fc2304e..d0dcf6d4c3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,8 @@ ## Latest Changes +## 0.13.1 + ### Features * ✨ Remove Rich tags when showing completion text. PR [#877](/~https://github.com/fastapi/typer/pull/877) by [@svlandeg](/~https://github.com/svlandeg). diff --git a/typer/__init__.py b/typer/__init__.py index 0ba5475321..cb24d1c768 100644 --- a/typer/__init__.py +++ b/typer/__init__.py @@ -1,6 +1,6 @@ """Typer, build great CLIs. Easy to code. Based on Python type hints.""" -__version__ = "0.13.0" +__version__ = "0.13.1" from shutil import get_terminal_size as get_terminal_size