diff --git a/cliff/app.py b/cliff/app.py index 57528a8..f68ca74 100644 --- a/cliff/app.py +++ b/cliff/app.py @@ -221,6 +221,18 @@ class App(object): self.options, remainder = self.parser.parse_known_args(argv) self.configure_logging() self.interactive_mode = not remainder + if self.deferred_help and self.options.deferred_help and remainder: + # When help is requested and `remainder` has any values disable + # `deferred_help` and instead allow the help subcommand to + # handle the request during run_subcommand(). This turns + # "app foo bar --help" into "app help foo bar". However, when + # `remainder` is empty use print_help_if_requested() to allow + # for an early exit. + # Disabling `deferred_help` here also ensures that + # print_help_if_requested will not fire if called by a subclass + # during its initialize_app(). + self.options.deferred_help = False + remainder.insert(0, "help") self.initialize_app(remainder) self.print_help_if_requested() except Exception as err: diff --git a/cliff/tests/test_app.py b/cliff/tests/test_app.py index 799e5ee..b4125df 100644 --- a/cliff/tests/test_app.py +++ b/cliff/tests/test_app.py @@ -401,6 +401,26 @@ def test_deferred_help(): _test_help(True) +def test_subcommand_help(): + app, _ = make_app(deferred_help=False) + + # Help is called immediately + with mock.patch('cliff.help.HelpAction.__call__') as helper: + app.run(['show', 'files', '--help']) + + assert helper.called + + +def test_subcommand_deferred_help(): + app, _ = make_app(deferred_help=True) + + # Show that provide_help_if_requested() did not show help and exit + with mock.patch.object(app, 'run_subcommand') as helper: + app.run(['show', 'files', '--help']) + + helper.assert_called_once_with(['help', 'show', 'files']) + + def test_unknown_cmd(): app, command = make_app() assert app.run(['hell']) == 2