From ece11118a42551b92f190f6aefb21eba9163d4d6 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 21 Aug 2024 18:06:46 +0200 Subject: [PATCH 1/5] commit failing test --- docs_src/commands/index/tutorial004.py | 17 +++++++ .../test_index/test_tutorial004.py | 45 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 docs_src/commands/index/tutorial004.py create mode 100644 tests/test_tutorial/test_commands/test_index/test_tutorial004.py diff --git a/docs_src/commands/index/tutorial004.py b/docs_src/commands/index/tutorial004.py new file mode 100644 index 0000000000..83419b695f --- /dev/null +++ b/docs_src/commands/index/tutorial004.py @@ -0,0 +1,17 @@ +import typer + +app = typer.Typer() + + +@app.command() +def delete(): + print("Deleting user: Hiro Hamada") + + +@app.command() +def create(): + print("Creating user: Hiro Hamada") + + +if __name__ == "__main__": + app() diff --git a/tests/test_tutorial/test_commands/test_index/test_tutorial004.py b/tests/test_tutorial/test_commands/test_index/test_tutorial004.py new file mode 100644 index 0000000000..ae0139e93a --- /dev/null +++ b/tests/test_tutorial/test_commands/test_index/test_tutorial004.py @@ -0,0 +1,45 @@ +import subprocess +import sys + +from typer.testing import CliRunner + +from docs_src.commands.index import tutorial004 as mod + +app = mod.app + +runner = CliRunner() + + +def test_help(): + result = runner.invoke(app, ["--help"]) + assert result.exit_code == 0 + assert "[OPTIONS] COMMAND [ARGS]..." in result.output + print(result.output) + assert "Commands" in result.output + assert "create" in result.output + assert "delete" in result.output + # Test that the 'delete' command precedes the 'create' command in the help output + create_char = result.output.index("create") + delete_char = result.output.index("delete") + assert delete_char < create_char + + +def test_create(): + result = runner.invoke(app, ["create"]) + assert result.exit_code == 0 + assert "Creating user: Hiro Hamada" in result.output + + +def test_delete(): + result = runner.invoke(app, ["delete"]) + assert result.exit_code == 0 + assert "Deleting user: Hiro Hamada" in result.output + + +def test_script(): + result = subprocess.run( + [sys.executable, "-m", "coverage", "run", mod.__file__, "--help"], + capture_output=True, + encoding="utf-8", + ) + assert "Usage" in result.stdout From a88eb3b50d078923dbe54b71efa65f86ae5b154c Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 21 Aug 2024 18:32:37 +0200 Subject: [PATCH 2/5] add list_commands function to TyperGroup to avoid sorting --- typer/core.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/typer/core.py b/typer/core.py index 31fece5a76..b9837dab9b 100644 --- a/typer/core.py +++ b/typer/core.py @@ -738,3 +738,9 @@ def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> Non ctx=ctx, markup_mode=self.rich_markup_mode, ) + + def list_commands(self, ctx: click.Context) -> list[str]: + """Returns a list of subcommand names. + Note that in Click's Group class, these are sorted. + In Typer, we wish to maintain the original order of creation (cf Issue #933)""" + return self.commands From 96e9ad77f271c75be4e2277a36b63db6348cf489 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 21 Aug 2024 18:46:31 +0200 Subject: [PATCH 3/5] add order explanation to the docs --- docs/tutorial/commands/index.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/tutorial/commands/index.md b/docs/tutorial/commands/index.md index d2693849d7..f531c7cfb3 100644 --- a/docs/tutorial/commands/index.md +++ b/docs/tutorial/commands/index.md @@ -257,6 +257,39 @@ Commands: + +## Sorting of the commands + +Note that by design, **Typer** shows the commands in the order they've been declared. + +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!} +``` + +Then we will see the `delete` command first in the help output: + +
+ +```console +// Check the help +$ python main.py --help + +Usage: main.py [OPTIONS] COMMAND [ARGS]... + +Options: + --install-completion Install completion for the current shell. + --show-completion Show completion for the current shell, to copy it or customize the installation. + --help Show this message and exit. + +Commands: + delete + create +``` + +
+ ## Click Group If you come from Click, a `typer.Typer` app with subcommands is more or less the equivalent of a Click Group. From 73936264d94fa6334687b4db0104c9d568824ee4 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 21 Aug 2024 18:56:22 +0200 Subject: [PATCH 4/5] fix typing --- typer/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/typer/core.py b/typer/core.py index b9837dab9b..c84c2b4962 100644 --- a/typer/core.py +++ b/typer/core.py @@ -739,8 +739,8 @@ def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> Non markup_mode=self.rich_markup_mode, ) - def list_commands(self, ctx: click.Context) -> list[str]: + def list_commands(self, ctx: click.Context) -> List[str]: """Returns a list of subcommand names. - Note that in Click's Group class, these are sorted. - In Typer, we wish to maintain the original order of creation (cf Issue #933)""" - return self.commands + Note that in Click's Group class, these are sorted. + In Typer, we wish to maintain the original order of creation (cf Issue #933)""" + return [n for n, c in self.commands.items()] From c7cccd7eee445f0f7bd11f3a16c43da4586c776d Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 23 Aug 2024 10:35:03 +0200 Subject: [PATCH 5/5] preliminary 'fix' for unit tests (WIP) --- tests/assets/cli/multiapp-docs-title.md | 32 ++++++++++++------------- tests/assets/cli/multiapp-docs.md | 32 ++++++++++++------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/assets/cli/multiapp-docs-title.md b/tests/assets/cli/multiapp-docs-title.md index e688a9ba91..ffde843736 100644 --- a/tests/assets/cli/multiapp-docs-title.md +++ b/tests/assets/cli/multiapp-docs-title.md @@ -18,41 +18,41 @@ The end **Commands**: -* `sub` * `top`: Top command +* `sub` -## `multiapp sub` +## `multiapp top` + +Top command **Usage**: ```console -$ multiapp sub [OPTIONS] COMMAND [ARGS]... +$ multiapp top [OPTIONS] ``` **Options**: * `--help`: Show this message and exit. -**Commands**: - -* `bye`: Say bye -* `hello`: Say Hello -* `hi`: Say Hi - -### `multiapp sub bye` - -Say bye +## `multiapp sub` **Usage**: ```console -$ multiapp sub bye [OPTIONS] +$ multiapp sub [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. +**Commands**: + +* `hello`: Say Hello +* `hi`: Say Hi +* `bye`: Say bye + ### `multiapp sub hello` Say Hello @@ -87,14 +87,14 @@ $ multiapp sub hi [OPTIONS] [USER] * `--help`: Show this message and exit. -## `multiapp top` +### `multiapp sub bye` -Top command +Say bye **Usage**: ```console -$ multiapp top [OPTIONS] +$ multiapp sub bye [OPTIONS] ``` **Options**: diff --git a/tests/assets/cli/multiapp-docs.md b/tests/assets/cli/multiapp-docs.md index ed4592f5c8..67d02568db 100644 --- a/tests/assets/cli/multiapp-docs.md +++ b/tests/assets/cli/multiapp-docs.md @@ -18,41 +18,41 @@ The end **Commands**: -* `sub` * `top`: Top command +* `sub` -## `multiapp sub` +## `multiapp top` + +Top command **Usage**: ```console -$ multiapp sub [OPTIONS] COMMAND [ARGS]... +$ multiapp top [OPTIONS] ``` **Options**: * `--help`: Show this message and exit. -**Commands**: - -* `bye`: Say bye -* `hello`: Say Hello -* `hi`: Say Hi - -### `multiapp sub bye` - -Say bye +## `multiapp sub` **Usage**: ```console -$ multiapp sub bye [OPTIONS] +$ multiapp sub [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. +**Commands**: + +* `hello`: Say Hello +* `hi`: Say Hi +* `bye`: Say bye + ### `multiapp sub hello` Say Hello @@ -87,14 +87,14 @@ $ multiapp sub hi [OPTIONS] [USER] * `--help`: Show this message and exit. -## `multiapp top` +### `multiapp sub bye` -Top command +Say bye **Usage**: ```console -$ multiapp top [OPTIONS] +$ multiapp sub bye [OPTIONS] ``` **Options**: