Allow subcommands to accept --help when using 'deferred_help'.

This patch changes how cliff handles help for subcommands but only when
'deferred_help' is enabled. Currently cliff consumes --help requests at the top
level. This means `myapp foo --help` and `myapp --help` produce the same output.
To get help for `foo` one must use `myapp help foo`. With this change
`myapp foo --help` will produce the same output as `myapp help foo` by
transforming the --help request into a help subcommand one. This is only done
when there are any options on the command line other than --help. When a top
level --help is requested the original behavior of print_help_if_requested()
is preserved.

Change-Id: I628bbfc383de516045288512cc023213d723a027
Closes-Bug: 1444983
This commit is contained in:
Sean Perry 2015-07-13 09:00:28 -07:00
parent b39e2f2922
commit 5d5aeb2f99
2 changed files with 32 additions and 0 deletions

View File

@ -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:

View File

@ -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