summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/cmd2.py65
-rw-r--r--tests/conftest.py2
-rw-r--r--tests/test_cmd2.py45
3 files changed, 48 insertions, 64 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 2a617a75..f0253c65 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -632,7 +632,7 @@ class Cmd(cmd.Cmd):
err_msg = err_color + err_msg + Fore.RESET
self.decolorized_write(sys.stderr, err_msg)
- if traceback_war:
+ if traceback_war and not self.debug:
war = "To enable full traceback, run the following command: 'set debug true'\n"
war = war_color + war + Fore.RESET
self.decolorized_write(sys.stderr, war)
@@ -1893,6 +1893,8 @@ class Cmd(cmd.Cmd):
try:
self.pipe_proc = subprocess.Popen(statement.pipe_to, stdin=subproc_stdin)
except Exception as ex:
+ self.perror('Not piping because - {}'.format(ex), traceback_war=False)
+
# Restore stdout to what it was and close the pipe
self.stdout.close()
subproc_stdin.close()
@@ -1901,8 +1903,6 @@ class Cmd(cmd.Cmd):
self.kept_state = None
self.redirecting = False
- # Re-raise the exception
- raise ex
elif statement.output:
import tempfile
if (not statement.output_to) and (not self.can_clip):
@@ -1920,7 +1920,7 @@ class Cmd(cmd.Cmd):
try:
sys.stdout = self.stdout = open(statement.output_to, mode)
except OSError as ex:
- self.perror('Not Redirecting because - {}'.format(ex), traceback_war=False)
+ self.perror('Not redirecting because - {}'.format(ex), traceback_war=False)
self.redirecting = False
else:
# going to a paste buffer
@@ -1998,18 +1998,29 @@ class Cmd(cmd.Cmd):
if statement.command in self.macros:
stop = self._run_macro(statement)
else:
- func = self.cmd_func(statement.command)
+ command = statement.command
+ func = self.cmd_func(command)
+ func_arg = statement.args
+
+ if not func and self.default_to_shell:
+ command = 'shell'
+ func = self.cmd_func(command)
+ func_arg = statement.command_and_args
+
if func:
- # Since we have a valid command store it in the history
- if statement.command not in self.exclude_from_history:
+ # Check if this command should be stored in the history
+ if command not in self.exclude_from_history:
self.history.append(statement.raw)
- stop = func(statement)
+ stop = func(func_arg)
else:
self.default(statement)
stop = False
+ if stop is None:
+ stop = False
+
return stop
def _run_macro(self, statement: Statement) -> bool:
@@ -2057,18 +2068,11 @@ class Cmd(cmd.Cmd):
return self.onecmd_plus_hooks(resolved)
def default(self, statement: Statement) -> None:
- """Executed when the command given isn't a recognized command implemented by a do_* method.
+ """Called on an input line when the command prefix is not recognized.
:param statement: Statement object with parsed input
"""
- if self.default_to_shell:
- result = os.system(statement.command_and_args)
- # If os.system() succeeded, then don't print warning about unknown command
- if not result:
- return
-
- # Print out a message stating this is an unknown command
- self.poutput('*** Unknown syntax: {}\n'.format(statement.command_and_args))
+ self.poutput('*** {} is not a recognized command, alias, or macro\n'.format(statement.command))
def pseudo_raw_input(self, prompt: str) -> str:
"""Began life as a copy of cmd's cmdloop; like raw_input but
@@ -2803,7 +2807,7 @@ class Cmd(cmd.Cmd):
:param args: argparse parsed arguments from the set command
:param parameter: optional search parameter
"""
- param = parameter.strip().lower()
+ param = utils.norm_fold(parameter.strip())
result = {}
maxlen = 0
@@ -2844,7 +2848,7 @@ class Cmd(cmd.Cmd):
# Check if param was passed in
if not args.param:
return self.show(args)
- param = args.param.strip().lower()
+ param = utils.norm_fold(args.param.strip())
# Check if value was passed in
if not args.value:
@@ -3156,15 +3160,19 @@ class Cmd(cmd.Cmd):
history_parser_group.add_argument('-e', '--edit', action='store_true',
help='edit and then run selected history items')
history_parser_group.add_argument('-s', '--script', action='store_true', help='output commands in script format')
- history_parser_group.add_argument('-o', '--output-file', metavar='FILE', help='output commands to a script file')
- history_parser_group.add_argument('-t', '--transcript', help='output commands and results to a transcript file')
+ setattr(history_parser_group.add_argument('-o', '--output-file', metavar='FILE',
+ help='output commands to a script file'),
+ ACTION_ARG_CHOICES, ('path_complete',))
+ setattr(history_parser_group.add_argument('-t', '--transcript',
+ help='output commands and results to a transcript file'),
+ ACTION_ARG_CHOICES, ('path_complete',))
history_parser_group.add_argument('-c', '--clear', action="store_true", help='clear all history')
- _history_arg_help = """empty all history items
-a one history item by number
-a..b, a:b, a:, ..b items by indices (inclusive)
-[string] items containing string
-/regex/ items matching regular expression"""
- history_parser.add_argument('arg', nargs='?', help=_history_arg_help)
+ history_arg_help = ("empty all history items\n"
+ "a one history item by number\n"
+ "a..b, a:b, a:, ..b items by indices (inclusive)\n"
+ "string items containing string\n"
+ "/regex/ items matching regular expression")
+ history_parser.add_argument('arg', nargs='?', help=history_arg_help)
@with_argparser(history_parser)
def do_history(self, args: argparse.Namespace) -> None:
@@ -3851,7 +3859,6 @@ class History(list):
end = int(end)
return self[start:end]
- # noinspection PyUnresolvedReferences
getme = getme.strip()
if getme.startswith(r'/') and getme.endswith(r'/'):
@@ -3871,7 +3878,7 @@ class History(list):
:param hi: HistoryItem
:return: bool - True if search matches
"""
- return getme.lower() in hi.lowercase
+ return utils.norm_fold(getme) in utils.norm_fold(hi)
return [itm for itm in self if isin(itm)]
diff --git a/tests/conftest.py b/tests/conftest.py
index da7e8b08..ac6a1896 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -59,7 +59,7 @@ positional arguments:
arg empty all history items
a one history item by number
a..b, a:b, a:, ..b items by indices (inclusive)
- [string] items containing string
+ string items containing string
/regex/ items matching regular expression
optional arguments:
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 9bb85ffe..59c6bb60 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -298,7 +298,7 @@ def test_pyscript_requires_an_argument(base_app, capsys):
def test_base_error(base_app):
out = run_cmd(base_app, 'meow')
- assert out == ["*** Unknown syntax: meow"]
+ assert "is not a recognized command" in out[0]
@pytest.fixture
@@ -803,8 +803,7 @@ def test_pipe_to_shell_error(base_app, capsys):
run_cmd(base_app, 'help | foobarbaz.this_does_not_exist')
out, err = capsys.readouterr()
assert not out
- expected_error = 'FileNotFoundError'
- assert err.startswith("EXCEPTION of type '{}' occurred with message:".format(expected_error))
+ assert err.startswith("ERROR: Not piping because")
@pytest.mark.skipif(not clipboard.can_clip,
@@ -1042,12 +1041,12 @@ def hook_failure():
def test_precmd_hook_success(base_app):
out = base_app.onecmd_plus_hooks('help')
- assert out is None
+ assert out is False
def test_precmd_hook_failure(hook_failure):
out = hook_failure.onecmd_plus_hooks('help')
- assert out == True
+ assert out is True
class SayApp(cmd2.Cmd):
@@ -1098,40 +1097,18 @@ class ShellApp(cmd2.Cmd):
super().__init__(*args, **kwargs)
self.default_to_shell = True
-@pytest.fixture
-def shell_app():
- app = ShellApp()
- app.stdout = utils.StdSim(app.stdout)
- return app
-
-def test_default_to_shell_unknown(shell_app):
- unknown_command = 'zyxcw23'
- out = run_cmd(shell_app, unknown_command)
- assert out == ["*** Unknown syntax: {}".format(unknown_command)]
-
-def test_default_to_shell_good(capsys):
- app = cmd2.Cmd()
- app.default_to_shell = True
+def test_default_to_shell(base_app, monkeypatch):
if sys.platform.startswith('win'):
line = 'dir'
else:
line = 'ls'
- statement = app.statement_parser.parse(line)
- retval = app.default(statement)
- assert not retval
- out, err = capsys.readouterr()
- assert out == ''
-
-def test_default_to_shell_failure(capsys):
- app = cmd2.Cmd()
- app.default_to_shell = True
- line = 'ls does_not_exist.xyz'
- statement = app.statement_parser.parse(line)
- retval = app.default(statement)
- assert not retval
- out, err = capsys.readouterr()
- assert out == "*** Unknown syntax: {}\n".format(line)
+ base_app.default_to_shell = True
+ m = mock.Mock()
+ monkeypatch.setattr("{}.Popen".format('subprocess'), m)
+ out = run_cmd(base_app, line)
+ assert out == []
+ assert m.called
def test_ansi_prompt_not_esacped(base_app):
from cmd2.rl_utils import rl_make_safe_prompt