From 40c4b1e66851e0725acbf2f45a519cb0dfcdd0c9 Mon Sep 17 00:00:00 2001 From: Tiago Nobrega Date: Fri, 6 Oct 2023 16:42:35 -0300 Subject: [PATCH] fix: better help for invalid command args (#95) Instead of handling it like an internal error, present the help message as we do in _get_dispatcher() (for e.g. invalid commands) and return the same return code. Fixes #89 --- craft_application/application.py | 6 +++++- tests/integration/test_application.py | 23 +++++++++++++++++++++++ tests/unit/test_application.py | 5 +++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/craft_application/application.py b/craft_application/application.py index 9cc64c02..3d152c59 100644 --- a/craft_application/application.py +++ b/craft_application/application.py @@ -280,7 +280,7 @@ def _get_dispatcher(self) -> _Dispatcher: return dispatcher - def run(self) -> int: + def run(self) -> int: # noqa: PLR0912 (too many branches due to error handling) """Bootstrap and run the application.""" dispatcher = self._get_dispatcher() craft_cli.emit.trace("Preparing application...") @@ -315,6 +315,10 @@ def run(self) -> int: # command runs in inner instance self.services.project = self.project return_code = dispatcher.run() or 0 + except craft_cli.ArgumentParsingError as err: + print(err, file=sys.stderr) # to stderr, as argparse normally does + craft_cli.emit.ended_ok() + return_code = 64 # Command line usage error from sysexits.h except KeyboardInterrupt as err: self._emit_error(craft_cli.CraftError("Interrupted."), cause=err) return_code = 128 + signal.SIGINT diff --git a/tests/integration/test_application.py b/tests/integration/test_application.py index 4c5cfaef..edc0f75d 100644 --- a/tests/integration/test_application.py +++ b/tests/integration/test_application.py @@ -15,6 +15,7 @@ import argparse import pathlib import shutil +import textwrap import craft_application import craft_cli @@ -207,3 +208,25 @@ def test_get_command_help(monkeypatch, emitter, capsys, app, cmd, help_param): stdout, stderr = capsys.readouterr() assert f"testcraft {cmd} [options]" in stderr + + +def test_invalid_command_argument(monkeypatch, capsys, app): + """Test help output when passing an invalid argument to a command.""" + monkeypatch.setattr("sys.argv", ["testcraft", "pack", "--invalid-argument"]) + + return_code = app.run() + + assert return_code == 64 # noqa: PLR2004 (Magic number used in comparison) + + expected_stderr = textwrap.dedent( + """\ + Usage: testcraft [options] command [args]... + Try 'testcraft pack -h' for help. + + Error: unrecognized arguments: --invalid-argument + + """ + ) + + stdout, stderr = capsys.readouterr() + assert stderr == expected_stderr diff --git a/tests/unit/test_application.py b/tests/unit/test_application.py index 2b53d64c..7f241250 100644 --- a/tests/unit/test_application.py +++ b/tests/unit/test_application.py @@ -370,6 +370,11 @@ def test_run_success_managed_inside_managed( (craft_parts.PartsError("unable to pull"), 1, "unable to pull\n"), (craft_providers.ProviderError("fail to launch"), 1, "fail to launch\n"), (Exception(), 70, "testcraft internal error: Exception()\n"), + ( + craft_cli.ArgumentParsingError("Argument parsing error"), + 64, + "Argument parsing error\n", + ), ], ) def test_run_error(