Skip to content

Commit 8e92f9d

Browse files
authored
Merge pull request #647 from python-cmd2/help_error
Help now writes to stderr when no help information is found
2 parents 177297a + a36f1ff commit 8e92f9d

File tree

3 files changed

+37
-10
lines changed

3 files changed

+37
-10
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
* Enhancements
33
* Added ability to include command name placeholders in the message printed when trying to run a disabled command.
44
* See docstring for ``disable_command()`` or ``disable_category()`` for more details.
5+
* Added instance attributes to customize error messages without having to override methods. Theses messages can
6+
also be colored.
7+
* `help_error` - the error that prints when no help information can be found
8+
* `default_error` - the error that prints when a non-existent command is run
9+
* Potentially breaking changes
10+
* The following commands now write to stderr instead of stdout when printing an error. This will make catching
11+
errors easier in pyscript.
12+
* ``do_help()`` - when no help information can be found
13+
* ``default()`` - in all cases since this is called when an invalid command name is run
14+
* ``_report_disabled_command_usage()`` - in all cases since this is called when a disabled command is run
15+
* Removed *** from beginning of error messages printed by `do_help()` and `default()`.
516

617
## 0.9.11 (March 13, 2019)
718
* Bug Fixes

cmd2/cmd2.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,12 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent
428428
# Used to keep track of whether a continuation prompt is being displayed
429429
self.at_continuation_prompt = False
430430

431+
# The error that prints when no help information can be found
432+
self.help_error = "No help on {}"
433+
434+
# The error that prints when a non-existent command is run
435+
self.default_error = "{} is not a recognized command, alias, or macro"
436+
431437
# If this string is non-empty, then this warning message will print if a broken pipe error occurs while printing
432438
self.broken_pipe_warning = ''
433439

@@ -2057,8 +2063,8 @@ def default(self, statement: Statement) -> Optional[bool]:
20572063

20582064
return self.do_shell(statement.command_and_args)
20592065
else:
2060-
self.perror('*** {} is not a recognized command, alias, or macro'.format(statement.command),
2061-
err_color=Fore.RESET, traceback_war=False)
2066+
err_msg = self.default_error.format(statement.command)
2067+
self.decolorized_write(sys.stderr, "{}\n".format(err_msg))
20622068

20632069
def pseudo_raw_input(self, prompt: str) -> str:
20642070
"""Began life as a copy of cmd's cmdloop; like raw_input but
@@ -2586,12 +2592,21 @@ def do_help(self, args: argparse.Namespace) -> None:
25862592
else:
25872593
# Getting help for a specific command
25882594
func = self.cmd_func(args.command)
2595+
help_func = getattr(self, HELP_FUNC_PREFIX + args.command, None)
2596+
2597+
# If the command function uses argparse, then use argparse's help
25892598
if func and hasattr(func, 'argparser'):
25902599
completer = AutoCompleter(getattr(func, 'argparser'), self)
25912600
tokens = [args.command] + args.subcommand
25922601
self.poutput(completer.format_help(tokens))
2602+
2603+
# If there is no help information then print an error
2604+
elif help_func is None and (func is None or not func.__doc__):
2605+
err_msg = self.help_error.format(args.command)
2606+
self.decolorized_write(sys.stderr, "{}\n".format(err_msg))
2607+
2608+
# Otherwise delegate to cmd base class do_help()
25932609
else:
2594-
# No special behavior needed, delegate to cmd base class do_help()
25952610
super().do_help(args.command)
25962611

25972612
def _help_menu(self, verbose: bool = False) -> None:
@@ -3719,7 +3734,7 @@ def _report_disabled_command_usage(self, *args, message_to_print: str, **kwargs)
37193734
:param message_to_print: the message reporting that the command is disabled
37203735
:param kwargs: not used
37213736
"""
3722-
self.perror(message_to_print, err_color=Fore.RESET, traceback_war=False)
3737+
self.decolorized_write(sys.stderr, "{}\n".format(message_to_print))
37233738

37243739
def cmdloop(self, intro: Optional[str] = None) -> None:
37253740
"""This is an outer wrapper around _cmdloop() which deals with extra features provided by cmd2.

tests/test_cmd2.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -952,10 +952,10 @@ def test_custom_help_menu(help_app):
952952
""")
953953
assert out == expected
954954

955-
def test_help_undocumented(help_app):
956-
out = run_cmd(help_app, 'help undoc')
957-
expected = normalize('*** No help on undoc')
958-
assert out == expected
955+
def test_help_undocumented(help_app, capsys):
956+
run_cmd(help_app, 'help undoc')
957+
out, err = capsys.readouterr()
958+
assert err.startswith("No help on undoc")
959959

960960
def test_help_overridden_method(help_app):
961961
out = run_cmd(help_app, 'help edit')
@@ -1787,8 +1787,9 @@ def test_macro_create_with_escaped_args(base_app, capsys):
17871787
assert out == normalize("Macro 'fake' created")
17881788

17891789
# Run the macro
1790-
out = run_cmd(base_app, 'fake')
1791-
assert 'No help on {1}' in out[0]
1790+
run_cmd(base_app, 'fake')
1791+
out, err = capsys.readouterr()
1792+
assert err.startswith('No help on {1}')
17921793

17931794
def test_macro_usage_with_missing_args(base_app, capsys):
17941795
# Create the macro

0 commit comments

Comments
 (0)