From 622dc26b6c03b839294ea0aacdee4a43ea659def Mon Sep 17 00:00:00 2001 From: Xuan Hu Date: Mon, 7 Aug 2023 02:09:02 +0000 Subject: [PATCH 1/3] Make single command as subcommands with documentation. --- src/serious_scaffold/cli.py | 12 ++++++++++++ src/{{ module_name }}/cli.py | 16 ---------------- src/{{ module_name }}/cli.py.jinja | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 16 deletions(-) delete mode 100644 src/{{ module_name }}/cli.py create mode 100644 src/{{ module_name }}/cli.py.jinja diff --git a/src/serious_scaffold/cli.py b/src/serious_scaffold/cli.py index 5a4957d9..255ec187 100644 --- a/src/serious_scaffold/cli.py +++ b/src/serious_scaffold/cli.py @@ -9,6 +9,18 @@ def run() -> None: """Run command.""" +# NOTE(huxuan): callback is required for single command as subcommand. +# And it is a convenient way to document the whole cli app. +# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/ + + +@app.callback() +def callback() -> None: + """CLI for Serious Scaffold Python.""" + + +# NOTE(huxuan): click object is used for document generation. +# Reference: https://github.com/tiangolo/typer/issues/200#issuecomment-796485787 typer_click_object = typer.main.get_command(app) diff --git a/src/{{ module_name }}/cli.py b/src/{{ module_name }}/cli.py deleted file mode 100644 index 5a4957d9..00000000 --- a/src/{{ module_name }}/cli.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Command Line Interface.""" -import typer - -app = typer.Typer() - - -@app.command() -def run() -> None: - """Run command.""" - - -typer_click_object = typer.main.get_command(app) - - -if __name__ == "__main__": - app() # pragma: no cover diff --git a/src/{{ module_name }}/cli.py.jinja b/src/{{ module_name }}/cli.py.jinja new file mode 100644 index 00000000..2d30def6 --- /dev/null +++ b/src/{{ module_name }}/cli.py.jinja @@ -0,0 +1,28 @@ +"""Command Line Interface.""" +import typer + +app = typer.Typer() + + +@app.command() +def run() -> None: + """Run command.""" + + +# NOTE(huxuan): callback is required for single command as subcommand. +# And it is a convenient way to document the whole cli app. +# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/ + + +@app.callback() +def callback() -> None: + """CLI for {{ project_name }}.""" + + +# NOTE(huxuan): click object is used for document generation. +# Reference: https://github.com/tiangolo/typer/issues/200#issuecomment-796485787 +typer_click_object = typer.main.get_command(app) + + +if __name__ == "__main__": + app() # pragma: no cover From 7b634a737bbf49847197139c588b8f30677f82f8 Mon Sep 17 00:00:00 2001 From: Xuan Hu Date: Mon, 7 Aug 2023 06:25:28 +0000 Subject: [PATCH 2/3] Fix test. --- src/serious_scaffold/cli.py | 15 ++++++++------- src/{{ module_name }}/cli.py.jinja | 15 ++++++++------- tests/cli_test.py | 9 ++++++++- tests/cli_test.py.jinja | 9 ++++++++- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/serious_scaffold/cli.py b/src/serious_scaffold/cli.py index 255ec187..bb0aa6d5 100644 --- a/src/serious_scaffold/cli.py +++ b/src/serious_scaffold/cli.py @@ -9,13 +9,14 @@ def run() -> None: """Run command.""" -# NOTE(huxuan): callback is required for single command as subcommand. -# And it is a convenient way to document the whole cli app. -# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/ - - -@app.callback() -def callback() -> None: +# NOTE(huxuan): callback is required for single command as a subcommand in typer. +# And it is a convenient way to document the cli here. +# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/#one-command-and-one-callback +# BTW, `no_args_is_help` is set to `True` to avoid error when invoking the cli with no +# subcommands. The default behavior is strange and might change in the future. +# Reference: https://github.com/tiangolo/typer/issues/328 +@app.callback(no_args_is_help=True) +def main() -> None: """CLI for Serious Scaffold Python.""" diff --git a/src/{{ module_name }}/cli.py.jinja b/src/{{ module_name }}/cli.py.jinja index 2d30def6..2f7b3a19 100644 --- a/src/{{ module_name }}/cli.py.jinja +++ b/src/{{ module_name }}/cli.py.jinja @@ -9,13 +9,14 @@ def run() -> None: """Run command.""" -# NOTE(huxuan): callback is required for single command as subcommand. -# And it is a convenient way to document the whole cli app. -# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/ - - -@app.callback() -def callback() -> None: +# NOTE(huxuan): callback is required for single command as a subcommand in typer. +# And it is a convenient way to document the cli here. +# Reference: https://typer.tiangolo.com/tutorial/commands/one-or-multiple/#one-command-and-one-callback +# BTW, `no_args_is_help` is set to `True` to avoid error when invoking the cli with no +# subcommands. The default behavior is strange and might change in the future. +# Reference: https://github.com/tiangolo/typer/issues/328 +@app.callback(no_args_is_help=True) +def main() -> None: """CLI for {{ project_name }}.""" diff --git a/tests/cli_test.py b/tests/cli_test.py index c140e4c8..b14489ba 100644 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -6,8 +6,15 @@ runner = CliRunner() -def test_app() -> None: +def test_cli() -> None: """Tests for cli.""" result = runner.invoke(app) assert result.exit_code == 0 assert not result.output + + +def test_cli_run() -> None: + """Tests for run subcommand of the cli.""" + result = runner.invoke(app, "run") + assert result.exit_code == 0 + assert not result.output diff --git a/tests/cli_test.py.jinja b/tests/cli_test.py.jinja index 3569f115..ee5c4c7d 100644 --- a/tests/cli_test.py.jinja +++ b/tests/cli_test.py.jinja @@ -6,8 +6,15 @@ from {{ module_name }}.cli import app runner = CliRunner() -def test_app() -> None: +def test_cli() -> None: """Tests for cli.""" result = runner.invoke(app) assert result.exit_code == 0 assert not result.output + + +def test_cli_run() -> None: + """Tests for run subcommand of the cli.""" + result = runner.invoke(app, "run") + assert result.exit_code == 0 + assert not result.output From 03e3edd0e63045095cf936de5025f2a0f918e0bc Mon Sep 17 00:00:00 2001 From: Xuan Hu Date: Mon, 7 Aug 2023 06:26:52 +0000 Subject: [PATCH 3/3] Fix tests. --- tests/cli_test.py | 2 +- tests/cli_test.py.jinja | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index b14489ba..8f7268e3 100644 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -10,7 +10,7 @@ def test_cli() -> None: """Tests for cli.""" result = runner.invoke(app) assert result.exit_code == 0 - assert not result.output + assert "Usage" in result.output def test_cli_run() -> None: diff --git a/tests/cli_test.py.jinja b/tests/cli_test.py.jinja index ee5c4c7d..09139c1b 100644 --- a/tests/cli_test.py.jinja +++ b/tests/cli_test.py.jinja @@ -10,7 +10,7 @@ def test_cli() -> None: """Tests for cli.""" result = runner.invoke(app) assert result.exit_code == 0 - assert not result.output + assert "Usage" in result.output def test_cli_run() -> None: