diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2019-07-18 14:52:42 -0400 |
---|---|---|
committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2019-07-18 14:52:42 -0400 |
commit | 8e656392c996e11642edbc5b4c6f96e4e614efeb (patch) | |
tree | 677108fc33446585f5e9618b6e9d4f8ce010cd56 /cmd2 | |
parent | 28acfbff590749c3356db528036877f16ffec4cf (diff) | |
download | cmd2-git-8e656392c996e11642edbc5b4c6f96e4e614efeb.tar.gz |
Revert "Added sigint protection while entering/leaving cmd2 and Python interactive shells."
This reverts commit 28acfbff590749c3356db528036877f16ffec4cf.
Diffstat (limited to 'cmd2')
-rw-r--r-- | cmd2/cmd2.py | 299 |
1 files changed, 117 insertions, 182 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index b13af6ea..1f07f2cb 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -38,7 +38,6 @@ import pickle import re import sys import threading -from code import InteractiveConsole from collections import namedtuple from contextlib import redirect_stdout from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple, Type, Union @@ -281,24 +280,6 @@ def with_argparser(argparser: argparse.ArgumentParser, *, return arg_decorator -class _SavedReadlineSettings: - """readline settings that are backed up when switching between readline environments""" - def __init__(self): - self.completer = None - self.delims = '' - self.basic_quotes = None - - -class _SavedCmd2Env: - """cmd2 environment settings that are backed up when entering an interactive Python shell""" - def __init__(self): - self.readline_settings = _SavedReadlineSettings() - self.readline_module = None - self.history = [] - self.sys_stdout = None - self.sys_stdin = None - - class EmbeddedConsoleExit(SystemExit): """Custom exception class for use with the py command.""" pass @@ -2237,13 +2218,15 @@ class Cmd(cmd.Cmd): return line.rstrip('\r\n') - def _set_up_cmd2_readline(self) -> _SavedReadlineSettings: - """ - Set up readline with cmd2-specific settings - :return: Class containing saved readline settings - """ - readline_settings = _SavedReadlineSettings() + def _cmdloop(self) -> None: + """Repeatedly issue a prompt, accept input, parse an initial prefix + off the received input, and dispatch to action methods, passing them + the remainder of the line as argument. + This serves the same role as cmd.cmdloop(). + """ + # An almost perfect copy from Cmd; however, the pseudo_raw_input portion + # has been split out so that it can be called separately if self.use_rawinput and self.completekey and rl_type != RlType.NONE: # Set up readline for our tab completion needs @@ -2251,10 +2234,10 @@ class Cmd(cmd.Cmd): # Set GNU readline's rl_basic_quote_characters to NULL so it won't automatically add a closing quote # We don't need to worry about setting rl_completion_suppress_quote since we never declared # rl_completer_quote_characters. - readline_settings.basic_quotes = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value + saved_basic_quotes = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value rl_basic_quote_characters.value = None - readline_settings.completer = readline.get_completer() + saved_completer = readline.get_completer() readline.set_completer(self.complete) # Break words on whitespace and quotes when tab completing @@ -2264,46 +2247,13 @@ class Cmd(cmd.Cmd): # If redirection is allowed, then break words on those characters too completer_delims += ''.join(constants.REDIRECTION_CHARS) - readline_settings.delims = readline.get_completer_delims() + saved_delims = readline.get_completer_delims() readline.set_completer_delims(completer_delims) # Enable tab completion readline.parse_and_bind(self.completekey + ": complete") - return readline_settings - - def _restore_readline(self, readline_settings: _SavedReadlineSettings): - """ - Restore readline settings - :param readline_settings: the readline settings to restore - """ - if self.use_rawinput and self.completekey and rl_type != RlType.NONE: - - # Restore what we changed in readline - readline.set_completer(readline_settings.completer) - readline.set_completer_delims(readline_settings.delims) - - if rl_type == RlType.GNU: - readline.set_completion_display_matches_hook(None) - rl_basic_quote_characters.value = readline_settings.basic_quotes - elif rl_type == RlType.PYREADLINE: - # noinspection PyUnresolvedReferences - readline.rl.mode._display_completions = orig_pyreadline_display - - def _cmdloop(self) -> None: - """Repeatedly issue a prompt, accept input, parse an initial prefix - off the received input, and dispatch to action methods, passing them - the remainder of the line as argument. - - This serves the same role as cmd.cmdloop(). - """ - readline_settings = None - try: - # Get sigint protection while we set up readline for cmd2 - with self.sigint_protection: - readline_settings = self._set_up_cmd2_readline() - # Run startup commands stop = self.runcmds_plus_hooks(self._startup_commands) self._startup_commands.clear() @@ -2322,10 +2272,18 @@ class Cmd(cmd.Cmd): # Run the command along with all associated pre and post hooks stop = self.onecmd_plus_hooks(line) finally: - # Get sigint protection while we restore readline settings - with self.sigint_protection: - if readline_settings is not None: - self._restore_readline(readline_settings) + if self.use_rawinput and self.completekey and rl_type != RlType.NONE: + + # Restore what we changed in readline + readline.set_completer(saved_completer) + readline.set_completer_delims(saved_delims) + + if rl_type == RlType.GNU: + readline.set_completion_display_matches_hook(None) + rl_basic_quote_characters.value = saved_basic_quotes + elif rl_type == RlType.PYREADLINE: + # noinspection PyUnresolvedReferences + readline.rl.mode._display_completions = orig_pyreadline_display # ----- Alias sub-command functions ----- @@ -2932,10 +2890,10 @@ class Cmd(cmd.Cmd): response, len(fulloptions))) return result - def _get_read_only_settings(self) -> str: - """Return a summary report of read-only settings which the user cannot modify at runtime. + def _cmdenvironment(self) -> str: + """Get a summary report of read-only settings which the user cannot modify at runtime. - :return: The report string + :return: summary report of read-only settings which the user cannot modify at runtime """ read_only_settings = """ Commands may be terminated with: {} @@ -2966,7 +2924,7 @@ class Cmd(cmd.Cmd): # If user has requested to see all settings, also show read-only settings if args.all: - self.poutput('\nRead only settings:{}'.format(self._get_read_only_settings())) + self.poutput('\nRead only settings:{}'.format(self._cmdenvironment())) else: self.perror("Parameter '{}' not supported (type 'set' for list of parameters).".format(param)) @@ -3074,108 +3032,6 @@ class Cmd(cmd.Cmd): sys.displayhook = sys.__displayhook__ sys.excepthook = sys.__excepthook__ - def _set_up_py_shell_env(self, interp: InteractiveConsole) -> _SavedCmd2Env: - """ - Set up interactive Python shell environment - :return: Class containing saved up cmd2 environment - """ - cmd2_env = _SavedCmd2Env() - - # Set up readline for Python shell - if rl_type != RlType.NONE: - # Save cmd2 history - for i in range(1, readline.get_current_history_length() + 1): - # noinspection PyArgumentList - cmd2_env.history.append(readline.get_history_item(i)) - - readline.clear_history() - - # Restore py's history - for item in self._py_history: - readline.add_history(item) - - if self.use_rawinput and self.completekey: - # Set up tab completion for the Python console - # rlcompleter relies on the default settings of the Python readline module - if rl_type == RlType.GNU: - cmd2_env.readline_settings.basic_quotes = ctypes.cast(rl_basic_quote_characters, - ctypes.c_void_p).value - rl_basic_quote_characters.value = orig_rl_basic_quotes - - if 'gnureadline' in sys.modules: - # rlcompleter imports readline by name, so it won't use gnureadline - # Force rlcompleter to use gnureadline instead so it has our settings and history - if 'readline' in sys.modules: - cmd2_env.readline_module = sys.modules['readline'] - - sys.modules['readline'] = sys.modules['gnureadline'] - - cmd2_env.readline_settings.delims = readline.get_completer_delims() - readline.set_completer_delims(orig_rl_delims) - - # rlcompleter will not need cmd2's custom display function - # This will be restored by cmd2 the next time complete() is called - if rl_type == RlType.GNU: - readline.set_completion_display_matches_hook(None) - elif rl_type == RlType.PYREADLINE: - # noinspection PyUnresolvedReferences - readline.rl.mode._display_completions = orig_pyreadline_display - - # Save off the current completer and set a new one in the Python console - # Make sure it tab completes from its locals() dictionary - cmd2_env.readline_settings.completer = readline.get_completer() - interp.runcode("from rlcompleter import Completer") - interp.runcode("import readline") - interp.runcode("readline.set_completer(Completer(locals()).complete)") - - # Set up sys module for the Python console - self._reset_py_display() - - cmd2_env.sys_stdout = sys.stdout - sys.stdout = self.stdout - - cmd2_env.sys_stdin = sys.stdin - sys.stdin = self.stdin - - return cmd2_env - - def _restore_cmd2_env(self, cmd2_env: _SavedCmd2Env) -> None: - """ - Restore cmd2 environment after exiting an interactive Python shell - :param cmd2_env: the environment settings to restore - """ - sys.stdout = cmd2_env.sys_stdout - sys.stdin = cmd2_env.sys_stdin - - # Set up readline for cmd2 - if rl_type != RlType.NONE: - # Save py's history - self._py_history.clear() - for i in range(1, readline.get_current_history_length() + 1): - # noinspection PyArgumentList - self._py_history.append(readline.get_history_item(i)) - - readline.clear_history() - - # Restore cmd2's history - for item in cmd2_env.history: - readline.add_history(item) - - if self.use_rawinput and self.completekey: - # Restore cmd2's tab completion settings - readline.set_completer(cmd2_env.readline_settings.completer) - readline.set_completer_delims(cmd2_env.readline_settings.delims) - - if rl_type == RlType.GNU: - rl_basic_quote_characters.value = cmd2_env.readline_settings.basic_quotes - - if 'gnureadline' in sys.modules: - # Restore what the readline module pointed to - if cmd2_env.readline_module is None: - del(sys.modules['readline']) - else: - sys.modules['readline'] = cmd2_env.readline_module - py_description = ("Invoke Python command or shell\n" "\n" "Note that, when invoking a command directly from the command line, this shell\n" @@ -3236,6 +3092,7 @@ class Cmd(cmd.Cmd): del self._pystate['self'] localvars = self._pystate + from code import InteractiveConsole interp = InteractiveConsole(locals=localvars) interp.runcode('import sys, os;sys.path.insert(0, os.getcwd())') @@ -3256,22 +3113,73 @@ class Cmd(cmd.Cmd): # We don't care about any exception that happened in the interactive console pass - # If there are no args, then we will open an interactive Python shell + # If there are no args, then we will open an interactive Python console else: + # Set up readline for Python console + if rl_type != RlType.NONE: + # Save cmd2 history + saved_cmd2_history = [] + for i in range(1, readline.get_current_history_length() + 1): + # noinspection PyArgumentList + saved_cmd2_history.append(readline.get_history_item(i)) + + readline.clear_history() + + # Restore py's history + for item in self._py_history: + readline.add_history(item) + + if self.use_rawinput and self.completekey: + # Set up tab completion for the Python console + # rlcompleter relies on the default settings of the Python readline module + if rl_type == RlType.GNU: + saved_basic_quotes = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value + rl_basic_quote_characters.value = orig_rl_basic_quotes + + if 'gnureadline' in sys.modules: + # rlcompleter imports readline by name, so it won't use gnureadline + # Force rlcompleter to use gnureadline instead so it has our settings and history + saved_readline = None + if 'readline' in sys.modules: + saved_readline = sys.modules['readline'] + + sys.modules['readline'] = sys.modules['gnureadline'] + + saved_delims = readline.get_completer_delims() + readline.set_completer_delims(orig_rl_delims) + + # rlcompleter will not need cmd2's custom display function + # This will be restored by cmd2 the next time complete() is called + if rl_type == RlType.GNU: + readline.set_completion_display_matches_hook(None) + elif rl_type == RlType.PYREADLINE: + # noinspection PyUnresolvedReferences + readline.rl.mode._display_completions = orig_pyreadline_display + + # Save off the current completer and set a new one in the Python console + # Make sure it tab completes from its locals() dictionary + saved_completer = readline.get_completer() + interp.runcode("from rlcompleter import Completer") + interp.runcode("import readline") + interp.runcode("readline.set_completer(Completer(locals()).complete)") + + # Set up sys module for the Python console + self._reset_py_display() + + saved_sys_stdout = sys.stdout + sys.stdout = self.stdout + + saved_sys_stdin = sys.stdin + sys.stdin = self.stdin + cprt = 'Type "help", "copyright", "credits" or "license" for more information.' instructions = ('End with `Ctrl-D` (Unix) / `Ctrl-Z` (Windows), `quit()`, `exit()`.\n' 'Non-Python commands can be issued with: {}("your command")\n' 'Run Python code from external script files with: run("script.py")' .format(self.pyscript_name)) - cmd2_env = None - # noinspection PyBroadException try: - # Get sigint protection while we set up the Python shell environment - with self.sigint_protection: - cmd2_env = self._set_up_py_shell_env(interp) - interp.interact(banner="Python {} on {}\n{}\n\n{}\n". format(sys.version, sys.platform, cprt, instructions)) except BaseException: @@ -3279,10 +3187,37 @@ class Cmd(cmd.Cmd): pass finally: - # Get sigint protection while we restore cmd2 environment settings - with self.sigint_protection: - if cmd2_env is not None: - self._restore_cmd2_env(cmd2_env) + sys.stdout = saved_sys_stdout + sys.stdin = saved_sys_stdin + + # Set up readline for cmd2 + if rl_type != RlType.NONE: + # Save py's history + self._py_history.clear() + for i in range(1, readline.get_current_history_length() + 1): + # noinspection PyArgumentList + self._py_history.append(readline.get_history_item(i)) + + readline.clear_history() + + # Restore cmd2's history + for item in saved_cmd2_history: + readline.add_history(item) + + if self.use_rawinput and self.completekey: + # Restore cmd2's tab completion settings + readline.set_completer(saved_completer) + readline.set_completer_delims(saved_delims) + + if rl_type == RlType.GNU: + rl_basic_quote_characters.value = saved_basic_quotes + + if 'gnureadline' in sys.modules: + # Restore what the readline module pointed to + if saved_readline is None: + del(sys.modules['readline']) + else: + sys.modules['readline'] = saved_readline except KeyboardInterrupt: pass |