From 7212b99fb08decdaa49040ad04041515eb7876a7 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Fri, 27 Feb 2026 00:25:17 -0500 Subject: [PATCH] Removed default_to_shell. --- CHANGELOG.md | 1 + cmd2/cmd2.py | 9 --------- docs/features/initialization.md | 1 - docs/features/misc.md | 20 -------------------- examples/cmd_as_argument.py | 2 -- examples/hooks.py | 2 -- tests/test_cmd2.py | 20 -------------------- tests/test_completion.py | 23 ----------------------- 8 files changed, 1 insertion(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 601e9112e..57307c6e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ prompt is displayed. - Replaced `async_alert()` and `async_update_prompt()` with a single function called `add_alert()`. This new function is thread-safe and does not require you to acquire a mutex before calling it like the previous functions did. + - Removed `Cmd.default_to_shell`. - Enhancements - New `cmd2.Cmd` parameters - **auto_suggest**: (boolean) if `True`, provide fish shell style auto-suggestions. These diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index ca199c95a..dd618fce8 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -413,7 +413,6 @@ def __init__( self.stdout = sys.stdout # Attributes which should NOT be dynamically settable via the set command at runtime - self.default_to_shell = False # Attempt to run unrecognized commands as shell commands self.allow_redirection = allow_redirection # Security setting to prevent redirection of stdout # If True, cmd2 treats redirected input (pipes/files) as an interactive session. @@ -2277,9 +2276,6 @@ def _perform_completion( completer_func = self.completedefault # type: ignore[assignment] # Not a recognized macro or command - # Check if this command should be run as a shell command - elif self.default_to_shell and command in utils.get_exes_in_path(command): - completer_func = self.path_complete else: completer_func = self.completedefault # type: ignore[assignment] @@ -3196,11 +3192,6 @@ def default(self, statement: Statement) -> bool | None: :param statement: Statement object with parsed input """ - if self.default_to_shell: - if 'shell' not in self.exclude_from_history: - self.history.append(statement) - return self.do_shell(statement.command_and_args) - err_msg = self.default_error.format(statement.command) if self.suggest_similar_command and (suggested_command := self._suggest_similar_command(statement.command)): err_msg += f"\n{self.default_suggestion_message.format(suggested_command)}" diff --git a/docs/features/initialization.md b/docs/features/initialization.md index 6700ae1b8..0e7100fe2 100644 --- a/docs/features/initialization.md +++ b/docs/features/initialization.md @@ -31,7 +31,6 @@ Here are instance attributes of `cmd2.Cmd` which developers might wish to overri - **debug**: if `True`, show full stack trace on error (Default: `False`) - **default_category**: if any command has been categorized, then all other commands that haven't been categorized will display under this section in the help output. - **default_error**: the error that prints when a non-existent command is run -- **default_to_shell**: if `True`, attempt to run unrecognized commands as shell commands (Default: `False`) - **disabled_commands**: commands that have been disabled from use. This is to support commands that are only available during specific states of the application. This dictionary's keys are the command names and its values are DisabledCommand objects. - **doc_header**: Set the header used for the help function's listing of documented functions - **echo**: if `True`, each command the user issues will be repeated to the screen before it is executed. This is particularly useful when running scripts. This behavior does not occur when running a command at the prompt. (Default: `False`) diff --git a/docs/features/misc.md b/docs/features/misc.md index 1915b3302..f358a5c57 100644 --- a/docs/features/misc.md +++ b/docs/features/misc.md @@ -54,23 +54,3 @@ See the definitions of these functions for descriptions of their arguments. See the `do_enable_commands()` and `do_disable_commands()` functions in the [help_categories.py](https://github.com/python-cmd2/cmd2/blob/main/examples/help_categories.py) example for a demonstration. - -## Default to shell - -Every `cmd2` application can execute operating-system level (shell) commands with `shell` or a `!` -shortcut: - - (Cmd) shell which python - /usr/bin/python - (Cmd) !which python - /usr/bin/python - -However, if the parameter `default_to_shell` is `True`, then _every_ thing entered which doesn't -match another command will be attempted on the operating system. Only if that attempt fails (i.e., -produces a nonzero return value) will the application's own `default` method be called. - - (Cmd) which python - /usr/bin/python - (Cmd) my dog has fleas - sh: my: not found - *** Unknown syntax: my dog has fleas diff --git a/examples/cmd_as_argument.py b/examples/cmd_as_argument.py index f86b4e90b..a9e24f25f 100755 --- a/examples/cmd_as_argument.py +++ b/examples/cmd_as_argument.py @@ -16,8 +16,6 @@ class CmdLineApp(cmd2.Cmd): """Example cmd2 application.""" - # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist - # default_to_shell = True # noqa: ERA001 MUMBLES = ('like', '...', 'um', 'er', 'hmmm', 'ahh') MUMBLE_FIRST = ('so', 'like', 'well') MUMBLE_LAST = ('right?',) diff --git a/examples/hooks.py b/examples/hooks.py index ccb9a8386..a1ed27f38 100755 --- a/examples/hooks.py +++ b/examples/hooks.py @@ -37,8 +37,6 @@ class CmdLineApp(cmd2.Cmd): """ - # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist - # default_to_shell = True # noqa: ERA001 def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index edbec24be..dde7b1dd8 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -1293,26 +1293,6 @@ def test_add_alert(base_app) -> None: assert len(base_app._alert_queue) == orig_num_alerts + 3 -class ShellApp(cmd2.Cmd): - def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) - self.default_to_shell = True - - -def test_default_to_shell(base_app, monkeypatch) -> None: - if sys.platform.startswith('win'): - line = 'dir' - else: - line = 'ls' - - base_app.default_to_shell = True - m = mock.Mock() - monkeypatch.setattr("{}.Popen".format('subprocess'), m) - out, _err = run_cmd(base_app, line) - assert out == [] - assert m.called - - def test_visible_prompt() -> None: app = cmd2.Cmd() diff --git a/tests/test_completion.py b/tests/test_completion.py index a17ce6a59..f2d882bbd 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -484,29 +484,6 @@ def test_path_completion_nomatch(cmd2_app, request) -> None: assert not completions -def test_default_to_shell_completion(cmd2_app, request) -> None: - cmd2_app.default_to_shell = True - test_dir = os.path.dirname(request.module.__file__) - - text = os.path.join(test_dir, 'conftest') - - if sys.platform == "win32": - command = 'calc.exe' - else: - command = 'egrep' - - # Make sure the command is on the testing system - assert command in utils.get_exes_in_path(command) - line = f'{command} {text}' - - endidx = len(line) - begidx = endidx - len(text) - - expected = [text + '.py'] - completions = cmd2_app.complete(text, line, begidx, endidx) - assert completions.to_strings() == Completions.from_values(expected).to_strings() - - def test_path_completion_no_text(cmd2_app) -> None: # Run path complete with no search text which should show what's in cwd text = ''