diff options
-rwxr-xr-x | cmd2.py | 17 | ||||
-rwxr-xr-x | examples/help_categories.py | 9 | ||||
-rw-r--r-- | tests/conftest.py | 18 | ||||
-rw-r--r-- | tests/test_cmd2.py | 103 |
4 files changed, 138 insertions, 9 deletions
@@ -2934,10 +2934,9 @@ Usage: Usage: unalias [-a] name [name ...] cmds_cats = {} for command in visible_commands: - if command in help_topics: - cmds_doc.append(command) - help_topics.remove(command) - elif getattr(self, self._func_named(command)).__doc__: + if command in help_topics or getattr(self, self._func_named(command)).__doc__: + if command in help_topics: + help_topics.remove(command) if hasattr(getattr(self, self._func_named(command)), HELP_CATEGORY): category = getattr(getattr(self, self._func_named(command)), HELP_CATEGORY) cmds_cats.setdefault(category, []) @@ -2972,7 +2971,7 @@ Usage: Usage: unalias [-a] name [name ...] widest = 0 # measure the commands for command in cmds: - width = wcswidth(command) + width = len(command) if width > widest: widest = width # add a 4-space pad @@ -2983,17 +2982,23 @@ Usage: Usage: unalias [-a] name [name ...] if self.ruler: self.stdout.write('{:{ruler}<{width}}\n'.format('', ruler=self.ruler, width=80)) + help_topics = self.get_help_topics() for command in cmds: # Attempt to locate the first documentation block doc = getattr(self, self._func_named(command)).__doc__ doc_block = [] found_first = False + in_usage = False for doc_line in doc.splitlines(): str(doc_line).strip() if len(doc_line.strip()) > 0: + if in_usage or doc_line.startswith('usage: '): + in_usage = True + continue doc_block.append(doc_line.strip()) found_first = True else: + in_usage = False if found_first: break @@ -3101,7 +3106,7 @@ Usage: Usage: unalias [-a] name [name ...] else: raise LookupError("Parameter '%s' not supported (type 'show' for list of parameters)." % param) - set_parser = argparse.ArgumentParser() + set_parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') set_parser.add_argument('settable', nargs='*', help='[param_name] [value]') diff --git a/examples/help_categories.py b/examples/help_categories.py index 2a88edba..8a33e62c 100755 --- a/examples/help_categories.py +++ b/examples/help_categories.py @@ -4,7 +4,8 @@ A sample application for tagging categories on commands. """ -from cmd2 import Cmd, categorize, __version__ +from cmd2 import Cmd, categorize, __version__, with_argparser +import argparse class HelpCategories(Cmd): @@ -51,6 +52,12 @@ class HelpCategories(Cmd): """Redeploy command""" self.poutput('Redeploy') + restart_parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) + restart_parser.add_argument('when', default='now', + choices=['now', 'later', 'sometime', 'whenever'], + help='Specify when to restart') + + @with_argparser(restart_parser) def do_restart(self, _): """Restart command""" self.poutput('Restart') diff --git a/tests/conftest.py b/tests/conftest.py index 58ec8ee0..4170a5e1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,6 +19,24 @@ alias help load pyscript set shortcuts edit history py quit shell unalias """ +BASE_HELP_VERBOSE = """ +Documented commands (type help <topic>): +================================================================================ +alias Define or display aliases +edit Edit a file in a text editor. +help List available commands with "help" or detailed help with "help cmd". +history View, run, edit, and save previously entered commands. +load Runs commands in script file that is encoded as either ASCII or UTF-8 text. +py Invoke python command, shell, or script +pyscript Runs a python script file inside the console +quit Exits this application. +set Sets a settable parameter or shows current settings of parameters. +shell Execute a command as if at the OS prompt. +shortcuts Lists shortcuts (aliases) available. +unalias Unsets aliases + +""" + # Help text for the history command HELP_HISTORY = """usage: history [-h] [-r | -e | -s | -o FILE | -t TRANSCRIPT] [arg] diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 545cf1aa..0861c073 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -21,7 +21,8 @@ from optparse import make_option import six.moves as sm import cmd2 -from conftest import run_cmd, normalize, BASE_HELP, HELP_HISTORY, SHORTCUTS_TXT, SHOW_TXT, SHOW_LONG, StdOut +from conftest import run_cmd, normalize, BASE_HELP, BASE_HELP_VERBOSE, \ + HELP_HISTORY, SHORTCUTS_TXT, SHOW_TXT, SHOW_LONG, StdOut def test_ver(): @@ -38,6 +39,13 @@ def test_base_help(base_app): expected = normalize(BASE_HELP) assert out == expected +def test_base_help_verbose(base_app): + out = run_cmd(base_app, 'help -v') + expected = normalize(BASE_HELP_VERBOSE) + assert out == expected + + out = run_cmd(base_app, 'help --verbose') + assert out == expected def test_base_help_history(base_app): out = run_cmd(base_app, 'help history') @@ -47,7 +55,7 @@ def test_base_argparse_help(base_app, capsys): # Verify that "set -h" gives the same output as "help set" and that it starts in a way that makes sense run_cmd(base_app, 'set -h') out, err = capsys.readouterr() - out1 = out.splitlines() + out1 = normalize(out) out2 = run_cmd(base_app, 'help set') @@ -1066,6 +1074,97 @@ def test_help_overridden_method(help_app): assert out == expected +class HelpCategoriesApp(cmd2.Cmd): + """Class for testing custom help_* methods which override docstring help.""" + def __init__(self, *args, **kwargs): + # Need to use this older form of invoking super class constructor to support Python 2.x and Python 3.x + cmd2.Cmd.__init__(self, *args, **kwargs) + + def do_diddly(self, arg): + """This command does diddly""" + pass + + cmd2.categorize(do_diddly, "Some Category") + + def do_squat(self, arg): + """This docstring help will never be shown because the help_squat method overrides it.""" + pass + + def help_squat(self): + self.stdout.write('This command does diddly squat...\n') + + def do_edit(self, arg): + """This overrides the edit command and does nothing.""" + pass + + cmd2.categorize((do_squat, do_edit), 'Custom Category') + + # This command will be in the "undocumented" section of the help menu + def do_undoc(self, arg): + pass + +@pytest.fixture +def helpcat_app(): + app = HelpCategoriesApp() + app.stdout = StdOut() + return app + +def test_help_cat_base(helpcat_app): + out = run_cmd(helpcat_app, 'help') + expected = normalize("""Documented commands (type help <topic>): + +Custom Category +=============== +edit squat + +Some Category +============= +diddly + +Other +===== +alias help history load py pyscript quit set shell shortcuts unalias + +Undocumented commands: +====================== +undoc +""") + assert out == expected + +def test_help_cat_verbose(helpcat_app): + out = run_cmd(helpcat_app, 'help --verbose') + expected = normalize("""Documented commands (type help <topic>): + +Custom Category +================================================================================ +edit This overrides the edit command and does nothing. +squat This docstring help will never be shown because the help_squat method overrides it. + +Some Category +================================================================================ +diddly This command does diddly + +Other +================================================================================ +alias Define or display aliases +help List available commands with "help" or detailed help with "help cmd". +history View, run, edit, and save previously entered commands. +load Runs commands in script file that is encoded as either ASCII or UTF-8 text. +py Invoke python command, shell, or script +pyscript Runs a python script file inside the console +quit Exits this application. +set Sets a settable parameter or shows current settings of parameters. +shell Execute a command as if at the OS prompt. +shortcuts Lists shortcuts (aliases) available. +unalias Unsets aliases + +Undocumented commands: +====================== +undoc +""") + assert out == expected + + class SelectApp(cmd2.Cmd): def do_eat(self, arg): """Eat something, with a selection of sauces to choose from.""" |