change help action to use its own exception for exit

Provide a new exception class for the help action to use to indicate
that the app should exit, instead of calling sys.exit(). This allows
argument parsing errors in interactive mode to print help without
exiting the entire application, while still being treated as a
short-cut to avoid every command plugin having to process argument
errors itself.

Change-Id: If882b305ff9186f97ece6c77ef8c1b888c24a72d
Story: 2008071
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2020-09-09 09:01:56 -04:00
parent 28c172f701
commit 7fdd7cb4c5
No known key found for this signature in database
GPG Key ID: 3B6D06A0C428437A
3 changed files with 20 additions and 8 deletions

View File

@ -400,6 +400,8 @@ class App(object):
cmd_parser = cmd.get_parser(full_name)
parsed_args = cmd_parser.parse_args(sub_argv)
result = cmd.run(parsed_args)
except help.HelpExit:
result = 0
except SystemExit as ex:
raise cmd2.exceptions.Cmd2ArgparseError from ex
except Exception as err:

View File

@ -12,14 +12,24 @@
import argparse
import inspect
import sys
import traceback
from . import command
from . import utils
class HelpExit(SystemExit):
"""Special exception type to trigger quick exit from the application
We subclass from SystemExit to preserve API compatibility for
anything that used to catch SystemExit, but use a different class
so that cliff's Application can tell the difference between
something trying to hard-exit and help saying it's done.
"""
class HelpAction(argparse.Action):
"""Provide a custom action so the -h and --help options
to the main app will print a list of the commands.
@ -65,7 +75,7 @@ class HelpAction(argparse.Action):
else:
dist_info = ''
app.stdout.write(' %-13s %s%s\n' % (name, one_liner, dist_info))
sys.exit(0)
raise HelpExit()
class HelpCommand(command.Command):

View File

@ -42,7 +42,7 @@ class TestHelp(base.TestBase):
parsed_args = parser.parse_args(['one'])
try:
help_cmd.run(parsed_args)
except SystemExit:
except help.HelpExit:
pass
self.assertEqual('TestParser', stdout.getvalue())
@ -60,7 +60,7 @@ class TestHelp(base.TestBase):
parsed_args = parser.parse_args(['t'])
try:
help_cmd.run(parsed_args)
except SystemExit:
except help.HelpExit:
pass
help_output = stdout.getvalue()
self.assertIn('Command "t" matches:', help_output)
@ -99,7 +99,7 @@ class TestHelp(base.TestBase):
parsed_args = parser.parse_args([])
try:
help_cmd.run(parsed_args)
except SystemExit:
except help.HelpExit:
pass
help_text = stdout.getvalue()
basecommand = os.path.split(sys.argv[0])[1]
@ -122,7 +122,7 @@ class TestHelp(base.TestBase):
app.NAME = 'test'
try:
app.run(['--help'])
except SystemExit:
except help.HelpExit:
pass
help_output = stdout.getvalue()
self.assertIn('two words', help_output)
@ -144,7 +144,7 @@ class TestHelp(base.TestBase):
parsed_args = parser.parse_args([])
try:
help_cmd.run(parsed_args)
except SystemExit:
except help.HelpExit:
pass
help_output = stdout.getvalue()
self.assertIn('Commands:', help_output)
@ -166,7 +166,7 @@ class TestHelp(base.TestBase):
parsed_args = parser.parse_args([])
try:
help_cmd.run(parsed_args)
except SystemExit:
except help.HelpExit:
pass
help_output = stdout.getvalue()
self.assertIn('Commands:', help_output)