diff options
Diffstat (limited to 'cmd2/cmd2.py')
-rw-r--r-- | cmd2/cmd2.py | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 6b085a98..d13f6335 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -68,7 +68,7 @@ else: if rl_type == RlType.PYREADLINE: # Save the original pyreadline display completion function since we need to override it and restore it - # noinspection PyProtectedMember + # noinspection PyProtectedMember,PyUnresolvedReferences orig_pyreadline_display = readline.rl.mode._display_completions elif rl_type == RlType.GNU: @@ -104,6 +104,7 @@ except ImportError: # Python 3.4 require contextlib2 for temporarily redirecting stderr and stdout if sys.version_info < (3, 5): + # noinspection PyUnresolvedReferences from contextlib2 import redirect_stdout else: from contextlib import redirect_stdout @@ -295,14 +296,10 @@ class Cmd(cmd.Cmd): Line-oriented command interpreters are often useful for test harnesses, internal tools, and rapid prototypes. """ - # Attributes used to configure the StatementParser, best not to change these at runtime - multiline_commands = [] - shortcuts = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'} - terminators = [constants.MULTILINE_TERMINATOR] + DEFAULT_SHORTCUTS = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'} # Attributes which are NOT dynamically settable at runtime allow_cli_args = True # Should arguments passed on the command-line be processed as commands? - allow_redirection = True # Should output redirection and pipes be allowed default_to_shell = False # Attempt to run unrecognized commands as shell commands quit_on_sigint = False # Quit the loop on interrupt instead of just resetting prompt reserved_words = [] @@ -340,7 +337,9 @@ class Cmd(cmd.Cmd): def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent_history_file: str = '', persistent_history_length: int = 1000, startup_script: Optional[str] = None, use_ipython: bool = False, - transcript_files: Optional[List[str]] = None) -> None: + transcript_files: Optional[List[str]] = None, allow_redirection: bool = True, + multiline_commands: Optional[List[str]] = None, terminators: Optional[List[str]] = None, + shortcuts: Optional[Dict[str, str]] = None) -> None: """An easy but powerful framework for writing line-oriented command interpreters, extends Python's cmd package. :param completekey: (optional) readline name of a completion key, default to Tab @@ -351,6 +350,9 @@ class Cmd(cmd.Cmd): :param startup_script: (optional) file path to a a script to load and execute at startup :param use_ipython: (optional) should the "ipy" command be included for an embedded IPython shell :param transcript_files: (optional) allows running transcript tests when allow_cli_args is False + :param allow_redirection: (optional) should output redirection and pipes be allowed + :param multiline_commands: (optional) list of commands allowed to accept multi-line input + :param shortcuts: (optional) dictionary containing shortcuts for commands """ # If use_ipython is False, make sure the do_ipy() method doesn't exit if not use_ipython: @@ -379,21 +381,21 @@ class Cmd(cmd.Cmd): self.aliases = dict() self.macros = dict() - self._finalize_app_parameters() - self.initial_stdout = sys.stdout self.history = History() self.pystate = {} self.py_history = [] self.pyscript_name = 'app' self.keywords = self.reserved_words + self.get_all_commands() - self.statement_parser = StatementParser( - allow_redirection=self.allow_redirection, - terminators=self.terminators, - multiline_commands=self.multiline_commands, - aliases=self.aliases, - shortcuts=self.shortcuts, - ) + + if shortcuts is None: + shortcuts = self.DEFAULT_SHORTCUTS + shortcuts = sorted(shortcuts.items(), reverse=True) + self.statement_parser = StatementParser(allow_redirection=allow_redirection, + terminators=terminators, + multiline_commands=multiline_commands, + aliases=self.aliases, + shortcuts=shortcuts) self._transcript_files = transcript_files # Used to enable the ability for a Python script to quit the application @@ -547,10 +549,15 @@ class Cmd(cmd.Cmd): """ return utils.strip_ansi(self.prompt) - def _finalize_app_parameters(self) -> None: - """Finalize the shortcuts""" - # noinspection PyUnresolvedReferences - self.shortcuts = sorted(self.shortcuts.items(), reverse=True) + @property + def allow_redirection(self) -> bool: + """Read-only property to get whether or not redirection of stdout is allowed.""" + return self.statement_parser.allow_redirection + + @property + def shortcuts(self) -> List[Tuple[str, str]]: + """Read-only property to access the shortcuts stored in the StatementParser.""" + return self.statement_parser.shortcuts def decolorized_write(self, fileobj: IO, msg: str) -> None: """Write a string to a fileobject, stripping ANSI escape sequences if necessary @@ -707,6 +714,7 @@ class Cmd(cmd.Cmd): if rl_type == RlType.GNU: readline.set_completion_display_matches_hook(self._display_matches_gnu_readline) elif rl_type == RlType.PYREADLINE: + # noinspection PyUnresolvedReferences readline.rl.mode._display_completions = self._display_matches_pyreadline def tokens_for_completion(self, line: str, begidx: int, endidx: int) -> Tuple[List[str], List[str]]: @@ -1334,6 +1342,7 @@ class Cmd(cmd.Cmd): # Print the header if one exists if self.completion_header: + # noinspection PyUnresolvedReferences readline.rl.mode.console.write('\n' + self.completion_header) # Display matches using actual display function. This also redraws the prompt and line. @@ -2182,6 +2191,7 @@ class Cmd(cmd.Cmd): readline.set_completion_display_matches_hook(None) rl_basic_quote_characters.value = old_basic_quotes elif rl_type == RlType.PYREADLINE: + # noinspection PyUnresolvedReferences readline.rl.mode._display_completions = orig_pyreadline_display self.cmdqueue.clear() @@ -2792,7 +2802,8 @@ class Cmd(cmd.Cmd): Commands may be terminated with: {} Arguments at invocation allowed: {} Output redirection and pipes allowed: {}""" - return read_only_settings.format(str(self.terminators), self.allow_cli_args, self.allow_redirection) + return read_only_settings.format(str(self.statement_parser.terminators), self.allow_cli_args, + self.allow_redirection) def show(self, args: argparse.Namespace, parameter: str = '') -> None: """Shows current settings of parameters. @@ -3017,6 +3028,7 @@ class Cmd(cmd.Cmd): # 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() @@ -3049,6 +3061,7 @@ class Cmd(cmd.Cmd): if rl_type == RlType.GNU: readline.set_completion_display_matches_hook(None) elif rl_type == RlType.PYREADLINE: + # noinspection PyUnresolvedReferences readline.rl.mode._display_completions = self._display_matches_pyreadline # Save off the current completer and set a new one in the Python console @@ -3086,6 +3099,7 @@ class Cmd(cmd.Cmd): # 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() @@ -3163,10 +3177,12 @@ class Cmd(cmd.Cmd): exit_msg = 'Leaving IPython, back to {}'.format(sys.argv[0]) if self.locals_in_py: - def load_ipy(self, app): + # noinspection PyUnusedLocal + def load_ipy(cmd2_instance, app): embed(banner1=banner, exit_msg=exit_msg) load_ipy(self, bridge) else: + # noinspection PyUnusedLocal def load_ipy(app): embed(banner1=banner, exit_msg=exit_msg) load_ipy(bridge) @@ -3568,6 +3584,7 @@ class Cmd(cmd.Cmd): if rl_type == RlType.GNU: sys.stderr.write(terminal_str) elif rl_type == RlType.PYREADLINE: + # noinspection PyUnresolvedReferences readline.rl.mode.console.write(terminal_str) # Redraw the prompt and input lines |