From 70bf9e1a12b89bb913c11fb07893ab4b9cab2576 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 15 Jun 2019 15:00:59 -0400 Subject: Began work to minimize public API --- cmd2/cmd2.py | 310 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 135 insertions(+), 175 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 46b098c5..062e6582 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -171,7 +171,7 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> def arg_decorator(func: Callable): @functools.wraps(func) def cmd_wrapper(cmd2_instance, statement: Union[Statement, str]): - _, parsed_arglist = cmd2_instance.statement_parser.get_command_arg_list(command_name, + _, parsed_arglist = cmd2_instance._statement_parser.get_command_arg_list(command_name, statement, preserve_quotes) @@ -210,7 +210,7 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *, def arg_decorator(func: Callable): @functools.wraps(func) def cmd_wrapper(cmd2_instance, statement: Union[Statement, str]): - statement, parsed_arglist = cmd2_instance.statement_parser.get_command_arg_list(command_name, + statement, parsed_arglist = cmd2_instance._statement_parser.get_command_arg_list(command_name, statement, preserve_quotes) @@ -268,7 +268,7 @@ def with_argparser(argparser: argparse.ArgumentParser, *, def arg_decorator(func: Callable): @functools.wraps(func) def cmd_wrapper(cmd2_instance, statement: Union[Statement, str]): - statement, parsed_arglist = cmd2_instance.statement_parser.get_command_arg_list(command_name, + statement, parsed_arglist = cmd2_instance._statement_parser.get_command_arg_list(command_name, statement, preserve_quotes) @@ -327,7 +327,6 @@ class Cmd(cmd.Cmd): Line-oriented command interpreters are often useful for test harnesses, internal tools, and rapid prototypes. """ - DEFAULT_SHORTCUTS = {'?': 'help', '!': 'shell', '@': 'run_script', '@@': '_relative_run_script'} DEFAULT_EDITOR = utils.find_editor() def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *, @@ -402,51 +401,46 @@ class Cmd(cmd.Cmd): # Commands to exclude from the history command # initialize history - self.persistent_history_length = persistent_history_length + self._persistent_history_length = persistent_history_length self._initialize_history(persistent_history_file) self.exclude_from_history = '''history edit eof'''.split() # Command aliases and macros self.macros = dict() - self.initial_stdout = sys.stdout - self.pystate = {} - self.py_history = [] + self._pystate = {} + self._py_history = [] self.pyscript_name = 'app' if shortcuts is None: - shortcuts = self.DEFAULT_SHORTCUTS + shortcuts = constants.DEFAULT_SHORTCUTS shortcuts = sorted(shortcuts.items(), reverse=True) - self.statement_parser = StatementParser(allow_redirection=allow_redirection, - terminators=terminators, - multiline_commands=multiline_commands, - shortcuts=shortcuts) + self._statement_parser = StatementParser(allow_redirection=allow_redirection, + terminators=terminators, + multiline_commands=multiline_commands, + shortcuts=shortcuts) # True if running inside a Python script or interactive console, False otherwise self._in_py = False - # Stores results from the last command run to enable usage of results in a Python script or interactive console - # Built-in commands don't make use of this. It is purely there for user-defined commands and convenience. - self._last_result = None - # Used by run_script command to store current script dir as a LIFO queue to support _relative_run_script command self._script_dir = [] # Context manager used to protect critical sections in the main thread from stopping due to a KeyboardInterrupt - self.sigint_protection = utils.ContextFlag() + self._sigint_protection = utils.ContextFlag() # If the current command created a process to pipe to, then this will be a ProcReader object. # Otherwise it will be None. Its used to know when a pipe process can be killed and/or waited upon. - self.cur_pipe_proc_reader = None + self._cur_pipe_proc_reader = None # Used by complete() for readline tab completion - self.completion_matches = [] + self._completion_matches = [] - # Used to keep track of whether we are redirecting or piping output - self.redirecting = False + # Used to keep track of whether we are _redirecting or piping output + self._redirecting = False # Used to keep track of whether a continuation prompt is being displayed - self.at_continuation_prompt = False + self._at_continuation_prompt = False # The error that prints when no help information can be found self.help_error = "No help on {}" @@ -535,7 +529,7 @@ class Cmd(cmd.Cmd): self.pager_chop = 'less -SRXF' # This boolean flag determines whether or not the cmd2 application can interact with the clipboard - self.can_clip = can_clip + self._can_clip = can_clip # This determines the value returned by cmdloop() when exiting the application self.exit_code = 0 @@ -543,7 +537,7 @@ class Cmd(cmd.Cmd): # This lock should be acquired before doing any asynchronous changes to the terminal to # ensure the updates to the terminal don't interfere with the input being typed or output # being printed by a command. - self.terminal_lock = threading.RLock() + self._terminal_lock = threading.RLock() # 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 @@ -566,24 +560,19 @@ class Cmd(cmd.Cmd): @property def aliases(self) -> Dict[str, str]: """Read-only property to access the aliases stored in the StatementParser.""" - return self.statement_parser.aliases - - @property - def shortcuts(self) -> Tuple[Tuple[str, str]]: - """Read-only property to access the shortcuts stored in the StatementParser.""" - return self.statement_parser.shortcuts + return self._statement_parser.aliases @property def allow_redirection(self) -> bool: """Getter for the allow_redirection property that determines whether or not redirection of stdout is allowed.""" - return self.statement_parser.allow_redirection + return self._statement_parser.allow_redirection @allow_redirection.setter def allow_redirection(self, value: bool) -> None: """Setter for the allow_redirection property that determines whether or not redirection of stdout is allowed.""" - self.statement_parser.allow_redirection = value + self._statement_parser.allow_redirection = value - def decolorized_write(self, fileobj: IO, msg: str) -> None: + def _decolorized_write(self, fileobj: IO, msg: str) -> None: """Write a string to a fileobject, stripping ANSI escape sequences if necessary Honor the current colors setting, which requires us to check whether the @@ -612,7 +601,7 @@ class Cmd(cmd.Cmd): msg_str += end if color: msg_str = color + msg_str + Fore.RESET - self.decolorized_write(self.stdout, msg_str) + self._decolorized_write(self.stdout, msg_str) except BrokenPipeError: # This occurs if a command's output is being piped to another # process and that process closes before the command is @@ -640,12 +629,12 @@ class Cmd(cmd.Cmd): else: err_msg = "{}\n".format(err) err_msg = err_color + err_msg + Fore.RESET - self.decolorized_write(sys.stderr, err_msg) + self._decolorized_write(sys.stderr, err_msg) 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) + self._decolorized_write(sys.stderr, war) def pfeedback(self, msg: str) -> None: """For printing nonessential feedback. Can be silenced with `quiet`. @@ -654,7 +643,7 @@ class Cmd(cmd.Cmd): if self.feedback_to_output: self.poutput(msg) else: - self.decolorized_write(sys.stderr, "{}\n".format(msg)) + self._decolorized_write(sys.stderr, "{}\n".format(msg)) def ppaged(self, msg: str, end: str = '\n', chop: bool = False) -> None: """Print output using a pager if it would go off screen and stdout isn't currently being redirected. @@ -687,9 +676,9 @@ class Cmd(cmd.Cmd): if sys.platform.startswith('win') or os.environ.get('TERM') is not None: functional_terminal = True - # Don't attempt to use a pager that can block if redirecting or running a script (either text or Python) + # Don't attempt to use a pager that can block if _redirecting or running a script (either text or Python) # Also only attempt to use a pager if actually running in a real fully functional terminal - if functional_terminal and not self.redirecting and not self._in_py and not self._script_dir: + if functional_terminal and not self._redirecting and not self._in_py and not self._script_dir: if self.colors.lower() == constants.COLORS_NEVER.lower(): msg_str = utils.strip_ansi(msg_str) @@ -699,11 +688,11 @@ class Cmd(cmd.Cmd): # Prevent KeyboardInterrupts while in the pager. The pager application will # still receive the SIGINT since it is in the same process group as us. - with self.sigint_protection: + with self._sigint_protection: pipe_proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE) pipe_proc.communicate(msg_str.encode('utf-8', 'replace')) else: - self.decolorized_write(self.stdout, msg_str) + self._decolorized_write(self.stdout, msg_str) except BrokenPipeError: # This occurs if a command's output is being piped to another process and that process closes before the # command is finished. If you would like your application to print a warning message, then set the @@ -713,7 +702,7 @@ class Cmd(cmd.Cmd): # ----- Methods related to tab completion ----- - def reset_completion_defaults(self) -> None: + def _reset_completion_defaults(self) -> None: """ Resets tab completion settings Needs to be called each time readline runs tab completion @@ -731,7 +720,7 @@ class Cmd(cmd.Cmd): # 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]]: + def _tokens_for_completion(self, line: str, begidx: int, endidx: int) -> Tuple[List[str], List[str]]: """ Used by tab completion functions to get all tokens through the one being completed :param line: the current input line with leading whitespace removed @@ -945,7 +934,7 @@ class Cmd(cmd.Cmd): :return: a list of possible tab completions """ # Get all tokens through the one being completed - tokens, _ = self.tokens_for_completion(line, begidx, endidx) + tokens, _ = self._tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -987,7 +976,7 @@ class Cmd(cmd.Cmd): :return: a list of possible tab completions """ # Get all tokens through the one being completed - tokens, _ = self.tokens_for_completion(line, begidx, endidx) + tokens, _ = self._tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -1157,35 +1146,6 @@ class Cmd(cmd.Cmd): return matches - @staticmethod - def get_exes_in_path(starts_with: str) -> List[str]: - """Returns names of executables in a user's path - - :param starts_with: what the exes should start with. leave blank for all exes in path. - :return: a list of matching exe names - """ - # Purposely don't match any executable containing wildcards - wildcards = ['*', '?'] - for wildcard in wildcards: - if wildcard in starts_with: - return [] - - # Get a list of every directory in the PATH environment variable and ignore symbolic links - paths = [p for p in os.getenv('PATH').split(os.path.pathsep) if not os.path.islink(p)] - - # Use a set to store exe names since there can be duplicates - exes_set = set() - - # Find every executable file in the user's path that matches the pattern - for path in paths: - full_path = os.path.join(path, starts_with) - matches = utils.files_from_glob_pattern(full_path + '*', access=os.X_OK) - - for match in matches: - exes_set.add(os.path.basename(match)) - - return list(exes_set) - def shell_cmd_complete(self, text: str, line: str, begidx: int, endidx: int, complete_blank: bool = False) -> List[str]: """Performs completion of executables either in a user's path or a given path @@ -1204,7 +1164,7 @@ class Cmd(cmd.Cmd): # If there are no path characters in the search text, then do shell command completion in the user's path if not text.startswith('~') and os.path.sep not in text: - return self.get_exes_in_path(text) + return utils.get_exes_in_path(text) # Otherwise look for executables in the given path else: @@ -1228,7 +1188,7 @@ class Cmd(cmd.Cmd): # Get all tokens through the one being completed. We want the raw tokens # so we can tell if redirection strings are quoted and ignore them. - _, raw_tokens = self.tokens_for_completion(line, begidx, endidx) + _, raw_tokens = self._tokens_for_completion(line, begidx, endidx) if not raw_tokens: return [] @@ -1382,7 +1342,7 @@ class Cmd(cmd.Cmd): import functools if state == 0 and rl_type != RlType.NONE: unclosed_quote = '' - self.reset_completion_defaults() + self._reset_completion_defaults() # lstrip the original line orig_line = readline.get_line_buffer() @@ -1399,7 +1359,7 @@ class Cmd(cmd.Cmd): # from text and update the indexes. This only applies if we are at the the beginning of the line. shortcut_to_restore = '' if begidx == 0: - for (shortcut, _) in self.shortcuts: + for (shortcut, _) in self._statement_parser.shortcuts: if text.startswith(shortcut): # Save the shortcut to restore later shortcut_to_restore = shortcut @@ -1413,7 +1373,7 @@ class Cmd(cmd.Cmd): if begidx > 0: # Parse the command line - statement = self.statement_parser.parse_command_only(line) + statement = self._statement_parser.parse_command_only(line) command = statement.command expanded_line = statement.command_and_args @@ -1433,12 +1393,12 @@ class Cmd(cmd.Cmd): line = expanded_line # Get all tokens through the one being completed - tokens, raw_tokens = self.tokens_for_completion(line, begidx, endidx) + tokens, raw_tokens = self._tokens_for_completion(line, begidx, endidx) # Check if we either had a parsing error or are trying to complete the command token # The latter can happen if " or ' was entered as the command if len(tokens) <= 1: - self.completion_matches = [] + self._completion_matches = [] return None # Text we need to remove from completions later @@ -1489,27 +1449,27 @@ class Cmd(cmd.Cmd): # A valid command was not entered else: # Check if this command should be run as a shell command - if self.default_to_shell and command in self.get_exes_in_path(command): + if self.default_to_shell and command in utils.get_exes_in_path(command): compfunc = self.path_complete else: compfunc = self.completedefault # Attempt tab completion for redirection first, and if that isn't occurring, # call the completer function for the current command - self.completion_matches = self._redirect_complete(text, line, begidx, endidx, compfunc) + self._completion_matches = self._redirect_complete(text, line, begidx, endidx, compfunc) - if self.completion_matches: + if self._completion_matches: # Eliminate duplicates - self.completion_matches = utils.remove_duplicates(self.completion_matches) + self._completion_matches = utils.remove_duplicates(self._completion_matches) self.display_matches = utils.remove_duplicates(self.display_matches) if not self.display_matches: - # Since self.display_matches is empty, set it to self.completion_matches + # Since self.display_matches is empty, set it to self._completion_matches # before we alter them. That way the suggestions will reflect how we parsed # the token being completed and not how readline did. import copy - self.display_matches = copy.copy(self.completion_matches) + self.display_matches = copy.copy(self._completion_matches) # Check if we need to add an opening quote if not unclosed_quote: @@ -1517,7 +1477,7 @@ class Cmd(cmd.Cmd): add_quote = False # This is the tab completion text that will appear on the command line. - common_prefix = os.path.commonprefix(self.completion_matches) + common_prefix = os.path.commonprefix(self._completion_matches) if self.matches_delimited: # Check if any portion of the display matches appears in the tab completion @@ -1530,36 +1490,36 @@ class Cmd(cmd.Cmd): add_quote = True # If there is a tab completion and any match has a space, then add an opening quote - elif common_prefix and any(' ' in match for match in self.completion_matches): + elif common_prefix and any(' ' in match for match in self._completion_matches): add_quote = True if add_quote: # Figure out what kind of quote to add and save it as the unclosed_quote - if any('"' in match for match in self.completion_matches): + if any('"' in match for match in self._completion_matches): unclosed_quote = "'" else: unclosed_quote = '"' - self.completion_matches = [unclosed_quote + match for match in self.completion_matches] + self._completion_matches = [unclosed_quote + match for match in self._completion_matches] # Check if we need to remove text from the beginning of tab completions elif text_to_remove: - self.completion_matches = \ - [match.replace(text_to_remove, '', 1) for match in self.completion_matches] + self._completion_matches = \ + [match.replace(text_to_remove, '', 1) for match in self._completion_matches] # Check if we need to restore a shortcut in the tab completions # so it doesn't get erased from the command line if shortcut_to_restore: - self.completion_matches = \ - [shortcut_to_restore + match for match in self.completion_matches] + self._completion_matches = \ + [shortcut_to_restore + match for match in self._completion_matches] else: # Complete token against anything a user can run - self.completion_matches = self.basic_complete(text, line, begidx, endidx, - self.get_commands_aliases_and_macros_for_completion()) + self._completion_matches = self.basic_complete(text, line, begidx, endidx, + self.get_commands_aliases_and_macros_for_completion()) # Handle single result - if len(self.completion_matches) == 1: + if len(self._completion_matches) == 1: str_to_append = '' # Add a closing quote if needed and allowed @@ -1570,16 +1530,16 @@ class Cmd(cmd.Cmd): if self.allow_appended_space and endidx == len(line): str_to_append += ' ' - self.completion_matches[0] += str_to_append + self._completion_matches[0] += str_to_append # Sort matches if they haven't already been sorted if not self.matches_sorted: - self.completion_matches.sort(key=self.matches_sort_key) + self._completion_matches.sort(key=self.matches_sort_key) self.display_matches.sort(key=self.matches_sort_key) self.matches_sorted = True try: - return self.completion_matches[state] + return self._completion_matches[state] except IndexError: return None @@ -1606,7 +1566,7 @@ class Cmd(cmd.Cmd): """Default completion function for argparse commands.""" completer = AutoCompleter(argparser, self) - tokens, _ = self.tokens_for_completion(line, begidx, endidx) + tokens, _ = self._tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -1666,12 +1626,12 @@ class Cmd(cmd.Cmd): :param signum: signal number :param frame """ - if self.cur_pipe_proc_reader is not None: + if self._cur_pipe_proc_reader is not None: # Pass the SIGINT to the current pipe process - self.cur_pipe_proc_reader.send_sigint() + self._cur_pipe_proc_reader.send_sigint() # Check if we are allowed to re-raise the KeyboardInterrupt - if not self.sigint_protection: + if not self._sigint_protection: raise KeyboardInterrupt("Got a keyboard interrupt") def precmd(self, statement: Statement) -> Statement: @@ -1692,7 +1652,7 @@ class Cmd(cmd.Cmd): :param line: line read by readline :return: tuple containing (command, args, line) """ - statement = self.statement_parser.parse_command_only(line) + statement = self._statement_parser.parse_command_only(line) return statement.command, statement.args, statement.command_and_args def onecmd_plus_hooks(self, line: str, pyscript_bridge_call: bool = False) -> bool: @@ -1732,27 +1692,27 @@ class Cmd(cmd.Cmd): # we need to run the finalization hooks raise EmptyStatement - # Keep track of whether or not we were already redirecting before this command - already_redirecting = self.redirecting + # Keep track of whether or not we were already _redirecting before this command + already_redirecting = self._redirecting # This will be a utils.RedirectionSavedState object for the command saved_state = None try: # Get sigint protection while we set up redirection - with self.sigint_protection: + with self._sigint_protection: if pyscript_bridge_call: # Start saving command's stdout at this point self.stdout.pause_storage = False redir_error, saved_state = self._redirect_output(statement) - self.cur_pipe_proc_reader = saved_state.pipe_proc_reader + self._cur_pipe_proc_reader = saved_state.pipe_proc_reader # Do not continue if an error occurred while trying to redirect if not redir_error: - # See if we need to update self.redirecting + # See if we need to update self._redirecting if not already_redirecting: - self.redirecting = saved_state.redirecting + self._redirecting = saved_state.redirecting timestart = datetime.datetime.now() @@ -1783,12 +1743,12 @@ class Cmd(cmd.Cmd): self.pfeedback('Elapsed: {}'.format(datetime.datetime.now() - timestart)) finally: # Get sigint protection while we restore stuff - with self.sigint_protection: + with self._sigint_protection: if saved_state is not None: self._restore_output(statement, saved_state) if not already_redirecting: - self.redirecting = False + self._redirecting = False if pyscript_bridge_call: # Stop saving command's stdout before command finalization hooks run @@ -1805,7 +1765,7 @@ class Cmd(cmd.Cmd): def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement]) -> bool: """Run the command finalization hooks""" - with self.sigint_protection: + with self._sigint_protection: if not sys.platform.startswith('win') and self.stdout.isatty(): # Before the next command runs, fix any terminal problems like those # caused by certain binary characters having been printed to it. @@ -1856,7 +1816,7 @@ class Cmd(cmd.Cmd): """ while True: try: - statement = self.statement_parser.parse(line) + statement = self._statement_parser.parse(line) if statement.multiline_command and statement.terminator: # we have a completed multiline command, we are done break @@ -1867,7 +1827,7 @@ class Cmd(cmd.Cmd): except ValueError: # we have unclosed quotation marks, lets parse only the command # and see if it's a multiline - statement = self.statement_parser.parse_command_only(line) + statement = self._statement_parser.parse_command_only(line) if not statement.multiline_command: # not a multiline command, so raise the exception raise @@ -1876,7 +1836,7 @@ class Cmd(cmd.Cmd): # - a multiline command with no terminator # - a multiline command with unclosed quotation marks try: - self.at_continuation_prompt = True + self._at_continuation_prompt = True newline = self.pseudo_raw_input(self.continuation_prompt) if newline == 'eof': # they entered either a blank line, or we hit an EOF @@ -1891,10 +1851,10 @@ class Cmd(cmd.Cmd): raise ex else: self.poutput('^C') - statement = self.statement_parser.parse('') + statement = self._statement_parser.parse('') break finally: - self.at_continuation_prompt = False + self._at_continuation_prompt = False if not statement.command: raise EmptyStatement() @@ -2001,7 +1961,7 @@ class Cmd(cmd.Cmd): redir_error = False # Initialize the saved state - saved_state = utils.RedirectionSavedState(self.stdout, sys.stdout, self.cur_pipe_proc_reader) + saved_state = utils.RedirectionSavedState(self.stdout, sys.stdout, self._cur_pipe_proc_reader) if not self.allow_redirection: return redir_error, saved_state @@ -2055,7 +2015,7 @@ class Cmd(cmd.Cmd): elif statement.output: import tempfile - if (not statement.output_to) and (not self.can_clip): + if (not statement.output_to) and (not self._can_clip): self.perror("Cannot redirect to paste buffer; install 'pyperclip' and re-run to enable", traceback_war=False) redir_error = True @@ -2109,11 +2069,11 @@ class Cmd(cmd.Cmd): sys.stdout = saved_state.saved_sys_stdout # Check if we need to wait for the process being piped to - if self.cur_pipe_proc_reader is not None: - self.cur_pipe_proc_reader.wait() + if self._cur_pipe_proc_reader is not None: + self._cur_pipe_proc_reader.wait() - # Restore cur_pipe_proc_reader. This always is done, regardless of whether this command redirected. - self.cur_pipe_proc_reader = saved_state.saved_pipe_proc_reader + # Restore _cur_pipe_proc_reader. This always is done, regardless of whether this command redirected. + self._cur_pipe_proc_reader = saved_state.saved_pipe_proc_reader def cmd_func(self, command: str) -> Optional[Callable]: """ @@ -2175,7 +2135,7 @@ class Cmd(cmd.Cmd): return self.do_shell(statement.command_and_args) else: err_msg = self.default_error.format(statement.command) - self.decolorized_write(sys.stderr, "{}\n".format(err_msg)) + self._decolorized_write(sys.stderr, "{}\n".format(err_msg)) def pseudo_raw_input(self, prompt: str) -> str: """Began life as a copy of cmd's cmdloop; like raw_input but @@ -2187,10 +2147,10 @@ class Cmd(cmd.Cmd): if self.use_rawinput: try: if sys.stdin.isatty(): - # Wrap in try since terminal_lock may not be locked when this function is called from unit tests + # Wrap in try since _terminal_lock may not be locked when this function is called from unit tests try: # A prompt is about to be drawn. Allow asynchronous changes to the terminal. - self.terminal_lock.release() + self._terminal_lock.release() except RuntimeError: pass @@ -2206,7 +2166,7 @@ class Cmd(cmd.Cmd): finally: if sys.stdin.isatty(): # The prompt is gone. Do not allow asynchronous changes to the terminal. - self.terminal_lock.acquire() + self._terminal_lock.acquire() else: if self.stdin.isatty(): # on a tty, print the prompt first, then read the line @@ -2302,7 +2262,7 @@ class Cmd(cmd.Cmd): """Create or overwrite an alias""" # Validate the alias name - valid, errmsg = self.statement_parser.is_valid_command(args.name) + valid, errmsg = self._statement_parser.is_valid_command(args.name) if not valid: self.perror("Invalid alias name: {}".format(errmsg), traceback_war=False) return @@ -2313,7 +2273,7 @@ class Cmd(cmd.Cmd): # Unquote redirection and terminator tokens tokens_to_unquote = constants.REDIRECTION_TOKENS - tokens_to_unquote.extend(self.statement_parser.terminators) + tokens_to_unquote.extend(self._statement_parser.terminators) utils.unquote_specific_tokens(args.command_args, tokens_to_unquote) # Build the alias value string @@ -2433,7 +2393,7 @@ class Cmd(cmd.Cmd): """Create or overwrite a macro""" # Validate the macro name - valid, errmsg = self.statement_parser.is_valid_command(args.name) + valid, errmsg = self._statement_parser.is_valid_command(args.name) if not valid: self.perror("Invalid macro name: {}".format(errmsg), traceback_war=False) return @@ -2448,7 +2408,7 @@ class Cmd(cmd.Cmd): # Unquote redirection and terminator tokens tokens_to_unquote = constants.REDIRECTION_TOKENS - tokens_to_unquote.extend(self.statement_parser.terminators) + tokens_to_unquote.extend(self._statement_parser.terminators) utils.unquote_specific_tokens(args.command_args, tokens_to_unquote) # Build the macro value string @@ -2643,7 +2603,7 @@ class Cmd(cmd.Cmd): """Completes the subcommand argument of help""" # Get all tokens through the one being completed - tokens, _ = self.tokens_for_completion(line, begidx, endidx) + tokens, _ = self._tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -2707,7 +2667,7 @@ class Cmd(cmd.Cmd): # If there is no help information then print an error elif help_func is None and (func is None or not func.__doc__): err_msg = self.help_error.format(args.command) - self.decolorized_write(sys.stderr, "{}\n".format(err_msg)) + self._decolorized_write(sys.stderr, "{}\n".format(err_msg)) # Otherwise delegate to cmd base class do_help() else: @@ -2841,7 +2801,7 @@ class Cmd(cmd.Cmd): @with_argparser(ACArgumentParser()) def do_shortcuts(self, _: argparse.Namespace) -> None: """List available shortcuts""" - result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.shortcuts)) + result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self._statement_parser.shortcuts)) self.poutput("Shortcuts for other commands:\n{}\n".format(result)) @with_argparser(ACArgumentParser(epilog=INTERNAL_COMMAND_EPILOG)) @@ -2910,7 +2870,7 @@ class Cmd(cmd.Cmd): read_only_settings = """ Commands may be terminated with: {} Output redirection and pipes allowed: {}""" - return read_only_settings.format(str(self.statement_parser.terminators), self.allow_redirection) + return read_only_settings.format(str(self._statement_parser.terminators), self.allow_redirection) def show(self, args: argparse.Namespace, parameter: str = '') -> None: """Shows current settings of parameters. @@ -3010,7 +2970,7 @@ class Cmd(cmd.Cmd): # Prevent KeyboardInterrupts while in the shell process. The shell process will # still receive the SIGINT since it is in the same process group as us. - with self.sigint_protection: + with self._sigint_protection: # For any stream that is a StdSim, we will use a pipe so we can capture its output proc = subprocess.Popen(expanded_command, stdout=subprocess.PIPE if isinstance(self.stdout, utils.StdSim) else self.stdout, @@ -3094,17 +3054,17 @@ class Cmd(cmd.Cmd): raise EmbeddedConsoleExit # Set up Python environment - self.pystate[self.pyscript_name] = bridge - self.pystate['run'] = py_run - self.pystate['quit'] = py_quit - self.pystate['exit'] = py_quit + self._pystate[self.pyscript_name] = bridge + self._pystate['run'] = py_run + self._pystate['quit'] = py_quit + self._pystate['exit'] = py_quit if self.locals_in_py: - self.pystate['self'] = self - elif 'self' in self.pystate: - del self.pystate['self'] + self._pystate['self'] = self + elif 'self' in self._pystate: + del self._pystate['self'] - localvars = self.pystate + localvars = self._pystate from code import InteractiveConsole interp = InteractiveConsole(locals=localvars) interp.runcode('import sys, os;sys.path.insert(0, os.getcwd())') @@ -3139,7 +3099,7 @@ class Cmd(cmd.Cmd): readline.clear_history() # Restore py's history - for item in self.py_history: + for item in self._py_history: readline.add_history(item) if self.use_rawinput and self.completekey: @@ -3206,10 +3166,10 @@ class Cmd(cmd.Cmd): # Set up readline for cmd2 if rl_type != RlType.NONE: # Save py's history - self.py_history.clear() + 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)) + self._py_history.append(readline.get_history_item(i)) readline.clear_history() @@ -3508,7 +3468,7 @@ class Cmd(cmd.Cmd): if not self.persistent_history_file: return - self.history.truncate(self.persistent_history_length) + self.history.truncate(self._persistent_history_length) try: with open(self.persistent_history_file, 'wb') as fobj: pickle.dump(self.history, fobj) @@ -3530,7 +3490,7 @@ class Cmd(cmd.Cmd): commands_run = 0 try: - with self.sigint_protection: + with self._sigint_protection: # Disable echo while we manually redirect stdout to a StringIO buffer saved_echo = self.echo saved_stdout = self.stdout @@ -3575,7 +3535,7 @@ class Cmd(cmd.Cmd): if stop: break finally: - with self.sigint_protection: + with self._sigint_protection: # Restore altered attributes to their original state self.echo = saved_echo self.stdout = saved_stdout @@ -3695,7 +3655,7 @@ class Cmd(cmd.Cmd): return self.runcmds_plus_hooks(script_commands) finally: - with self.sigint_protection: + with self._sigint_protection: # Check if a script dir was added before an exception occurred if orig_script_dir_count != len(self._script_dir): self._script_dir.pop() @@ -3768,7 +3728,7 @@ class Cmd(cmd.Cmd): runner = unittest.TextTestRunner(stream=stream) test_results = runner.run(testcase) if test_results.wasSuccessful(): - self.decolorized_write(sys.stderr, stream.read()) + self._decolorized_write(sys.stderr, stream.read()) self.poutput('Tests passed', color=Fore.LIGHTGREEN_EX) else: # Strip off the initial traceback which isn't particularly useful for end users @@ -3789,14 +3749,14 @@ class Cmd(cmd.Cmd): To the user it appears as if an alert message is printed above the prompt and their current input text and cursor location is left alone. - IMPORTANT: This function will not print an alert unless it can acquire self.terminal_lock to ensure + IMPORTANT: This function will not print an alert unless it can acquire self._terminal_lock to ensure a prompt is onscreen. Therefore it is best to acquire the lock before calling this function to guarantee the alert prints. :param alert_msg: the message to display to the user :param new_prompt: if you also want to change the prompt that is displayed, then include it here see async_update_prompt() docstring for guidance on updating a prompt - :raises RuntimeError if called while another thread holds terminal_lock + :raises RuntimeError if called while another thread holds _terminal_lock """ if not (vt100_support and self.use_rawinput): return @@ -3805,11 +3765,11 @@ class Cmd(cmd.Cmd): import colorama.ansi as ansi from colorama import Cursor - # Sanity check that can't fail if self.terminal_lock was acquired before calling this function - if self.terminal_lock.acquire(blocking=False): + # Sanity check that can't fail if self._terminal_lock was acquired before calling this function + if self._terminal_lock.acquire(blocking=False): # Figure out what prompt is displaying - current_prompt = self.continuation_prompt if self.at_continuation_prompt else self.prompt + current_prompt = self.continuation_prompt if self._at_continuation_prompt else self.prompt # Only update terminal if there are changes update_terminal = False @@ -3823,7 +3783,7 @@ class Cmd(cmd.Cmd): self.prompt = new_prompt # If we aren't at a continuation prompt, then it's OK to update it - if not self.at_continuation_prompt: + if not self._at_continuation_prompt: rl_set_prompt(self.prompt) update_terminal = True @@ -3881,10 +3841,10 @@ class Cmd(cmd.Cmd): # Redraw the prompt and input lines rl_force_redisplay() - self.terminal_lock.release() + self._terminal_lock.release() else: - raise RuntimeError("another thread holds terminal_lock") + raise RuntimeError("another thread holds _terminal_lock") def async_update_prompt(self, new_prompt: str) -> None: # pragma: no cover """ @@ -3894,7 +3854,7 @@ class Cmd(cmd.Cmd): it is best to keep the prompt the same width as what's on screen. Otherwise the user's input text will be shifted and the update will not be seamless. - IMPORTANT: This function will not update the prompt unless it can acquire self.terminal_lock to ensure + IMPORTANT: This function will not update the prompt unless it can acquire self._terminal_lock to ensure a prompt is onscreen. Therefore it is best to acquire the lock before calling this function to guarantee the prompt changes. @@ -3903,7 +3863,7 @@ class Cmd(cmd.Cmd): and display immediately after the multiline line command completes. :param new_prompt: what to change the prompt to - :raises RuntimeError if called while another thread holds terminal_lock + :raises RuntimeError if called while another thread holds _terminal_lock """ self.async_alert('', new_prompt) @@ -3911,18 +3871,18 @@ class Cmd(cmd.Cmd): """ Set the terminal window title - IMPORTANT: This function will not set the title unless it can acquire self.terminal_lock to avoid + IMPORTANT: This function will not set the title unless it can acquire self._terminal_lock to avoid writing to stderr while a command is running. Therefore it is best to acquire the lock before calling this function to guarantee the title changes. :param title: the new window title - :raises RuntimeError if called while another thread holds terminal_lock + :raises RuntimeError if called while another thread holds _terminal_lock """ if not vt100_support: return - # Sanity check that can't fail if self.terminal_lock was acquired before calling this function - if self.terminal_lock.acquire(blocking=False): + # Sanity check that can't fail if self._terminal_lock was acquired before calling this function + if self._terminal_lock.acquire(blocking=False): try: import colorama.ansi as ansi sys.stderr.write(ansi.set_title(title)) @@ -3930,10 +3890,10 @@ class Cmd(cmd.Cmd): # Debugging in Pycharm has issues with setting terminal title pass finally: - self.terminal_lock.release() + self._terminal_lock.release() else: - raise RuntimeError("another thread holds terminal_lock") + raise RuntimeError("another thread holds _terminal_lock") def enable_command(self, command: str) -> None: """ @@ -4027,7 +3987,7 @@ class Cmd(cmd.Cmd): :param message_to_print: the message reporting that the command is disabled :param kwargs: not used """ - self.decolorized_write(sys.stderr, "{}\n".format(message_to_print)) + self._decolorized_write(sys.stderr, "{}\n".format(message_to_print)) def cmdloop(self, intro: Optional[str] = None) -> int: """This is an outer wrapper around _cmdloop() which deals with extra features provided by cmd2. @@ -4051,7 +4011,7 @@ class Cmd(cmd.Cmd): signal.signal(signal.SIGINT, self.sigint_handler) # Grab terminal lock before the prompt has been drawn by readline - self.terminal_lock.acquire() + self._terminal_lock.acquire() # Always run the preloop first for func in self._preloop_hooks: @@ -4080,7 +4040,7 @@ class Cmd(cmd.Cmd): # Release terminal lock now that postloop code should have stopped any terminal updater threads # This will also zero the lock count in case cmdloop() is called again - self.terminal_lock.release() + self._terminal_lock.release() # Restore the original signal handler signal.signal(signal.SIGINT, original_sigint_handler) -- cgit v1.2.1 From e538d1ac0ae0f121860c376be0ec059cdf797ce5 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 15 Jun 2019 15:05:22 -0400 Subject: Fix flake8 errors for continuation line under-indented after refactoring --- cmd2/cmd2.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 062e6582..d9a3fd8f 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -172,8 +172,8 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> @functools.wraps(func) def cmd_wrapper(cmd2_instance, statement: Union[Statement, str]): _, parsed_arglist = cmd2_instance._statement_parser.get_command_arg_list(command_name, - statement, - preserve_quotes) + statement, + preserve_quotes) return func(cmd2_instance, parsed_arglist) @@ -211,8 +211,8 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *, @functools.wraps(func) def cmd_wrapper(cmd2_instance, statement: Union[Statement, str]): statement, parsed_arglist = cmd2_instance._statement_parser.get_command_arg_list(command_name, - statement, - preserve_quotes) + statement, + preserve_quotes) if ns_provider is None: namespace = None @@ -269,8 +269,8 @@ def with_argparser(argparser: argparse.ArgumentParser, *, @functools.wraps(func) def cmd_wrapper(cmd2_instance, statement: Union[Statement, str]): statement, parsed_arglist = cmd2_instance._statement_parser.get_command_arg_list(command_name, - statement, - preserve_quotes) + statement, + preserve_quotes) if ns_provider is None: namespace = None -- cgit v1.2.1 From 52ea5e4a6bf22a0f1dfb498b5cbe863fbc69faab Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 15 Jun 2019 15:41:47 -0400 Subject: Made more methods protected --- cmd2/cmd2.py | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index d9a3fd8f..4e7a7a5d 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1837,7 +1837,7 @@ class Cmd(cmd.Cmd): # - a multiline command with unclosed quotation marks try: self._at_continuation_prompt = True - newline = self.pseudo_raw_input(self.continuation_prompt) + newline = self._pseudo_raw_input(self.continuation_prompt) if newline == 'eof': # they entered either a blank line, or we hit an EOF # for some other reason. Turn the literal 'eof' @@ -2137,7 +2137,7 @@ class Cmd(cmd.Cmd): err_msg = self.default_error.format(statement.command) self._decolorized_write(sys.stderr, "{}\n".format(err_msg)) - def pseudo_raw_input(self, prompt: str) -> str: + def _pseudo_raw_input(self, prompt: str) -> str: """Began life as a copy of cmd's cmdloop; like raw_input but - accounts for changed stdin, stdout @@ -2232,7 +2232,7 @@ class Cmd(cmd.Cmd): while not stop: # Get commands from user try: - line = self.pseudo_raw_input(self.prompt) + line = self._pseudo_raw_input(self.prompt) except KeyboardInterrupt as ex: if self.quit_on_sigint: raise ex @@ -2258,7 +2258,7 @@ class Cmd(cmd.Cmd): # ----- Alias sub-command functions ----- - def alias_create(self, args: argparse.Namespace) -> None: + def _alias_create(self, args: argparse.Namespace) -> None: """Create or overwrite an alias""" # Validate the alias name @@ -2286,7 +2286,7 @@ class Cmd(cmd.Cmd): self.aliases[args.name] = value self.poutput("Alias '{}' {}".format(args.name, result)) - def alias_delete(self, args: argparse.Namespace) -> None: + def _alias_delete(self, args: argparse.Namespace) -> None: """Delete aliases""" if args.all: self.aliases.clear() @@ -2301,7 +2301,7 @@ class Cmd(cmd.Cmd): else: self.perror("Alias '{}' does not exist".format(cur_name), traceback_war=False) - def alias_list(self, args: argparse.Namespace) -> None: + def _alias_list(self, args: argparse.Namespace) -> None: """List some or all aliases""" if args.name: for cur_name in utils.remove_duplicates(args.name): @@ -2350,7 +2350,7 @@ class Cmd(cmd.Cmd): setattr(alias_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command'), ACTION_ARG_CHOICES, ('path_complete',)) - alias_create_parser.set_defaults(func=alias_create) + alias_create_parser.set_defaults(func=_alias_create) # alias -> delete alias_delete_help = "delete aliases" @@ -2360,7 +2360,7 @@ class Cmd(cmd.Cmd): setattr(alias_delete_parser.add_argument('name', nargs='*', help='alias to delete'), ACTION_ARG_CHOICES, get_alias_names) alias_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all aliases") - alias_delete_parser.set_defaults(func=alias_delete) + alias_delete_parser.set_defaults(func=_alias_delete) # alias -> list alias_list_help = "list aliases" @@ -2373,7 +2373,7 @@ class Cmd(cmd.Cmd): description=alias_list_description) setattr(alias_list_parser.add_argument('name', nargs="*", help='alias to list'), ACTION_ARG_CHOICES, get_alias_names) - alias_list_parser.set_defaults(func=alias_list) + alias_list_parser.set_defaults(func=_alias_list) # Preserve quotes since we are passing strings to other commands @with_argparser(alias_parser, preserve_quotes=True) @@ -2389,7 +2389,7 @@ class Cmd(cmd.Cmd): # ----- Macro sub-command functions ----- - def macro_create(self, args: argparse.Namespace) -> None: + def _macro_create(self, args: argparse.Namespace) -> None: """Create or overwrite a macro""" # Validate the macro name @@ -2467,7 +2467,7 @@ class Cmd(cmd.Cmd): self.macros[args.name] = Macro(name=args.name, value=value, minimum_arg_count=max_arg_num, arg_list=arg_list) self.poutput("Macro '{}' {}".format(args.name, result)) - def macro_delete(self, args: argparse.Namespace) -> None: + def _macro_delete(self, args: argparse.Namespace) -> None: """Delete macros""" if args.all: self.macros.clear() @@ -2482,7 +2482,7 @@ class Cmd(cmd.Cmd): else: self.perror("Macro '{}' does not exist".format(cur_name), traceback_war=False) - def macro_list(self, args: argparse.Namespace) -> None: + def _macro_list(self, args: argparse.Namespace) -> None: """List some or all macros""" if args.name: for cur_name in utils.remove_duplicates(args.name): @@ -2554,7 +2554,7 @@ class Cmd(cmd.Cmd): setattr(macro_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command'), ACTION_ARG_CHOICES, ('path_complete',)) - macro_create_parser.set_defaults(func=macro_create) + macro_create_parser.set_defaults(func=_macro_create) # macro -> delete macro_delete_help = "delete macros" @@ -2564,7 +2564,7 @@ class Cmd(cmd.Cmd): setattr(macro_delete_parser.add_argument('name', nargs='*', help='macro to delete'), ACTION_ARG_CHOICES, get_macro_names) macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros") - macro_delete_parser.set_defaults(func=macro_delete) + macro_delete_parser.set_defaults(func=_macro_delete) # macro -> list macro_list_help = "list macros" @@ -2576,7 +2576,7 @@ class Cmd(cmd.Cmd): macro_list_parser = macro_subparsers.add_parser('list', help=macro_list_help, description=macro_list_description) setattr(macro_list_parser.add_argument('name', nargs="*", help='macro to list'), ACTION_ARG_CHOICES, get_macro_names) - macro_list_parser.set_defaults(func=macro_list) + macro_list_parser.set_defaults(func=_macro_list) # Preserve quotes since we are passing strings to other commands @with_argparser(macro_parser, preserve_quotes=True) @@ -2862,7 +2862,7 @@ class Cmd(cmd.Cmd): len(fulloptions))) return result - def cmdenvironment(self) -> str: + def _cmdenvironment(self) -> str: """Get a summary report of read-only settings which the user cannot modify at runtime. :return: summary report of read-only settings which the user cannot modify at runtime @@ -2872,7 +2872,7 @@ class Cmd(cmd.Cmd): Output redirection and pipes allowed: {}""" return read_only_settings.format(str(self._statement_parser.terminators), self.allow_redirection) - def show(self, args: argparse.Namespace, parameter: str = '') -> None: + def _show(self, args: argparse.Namespace, parameter: str = '') -> None: """Shows current settings of parameters. :param args: argparse parsed arguments from the set command @@ -2896,7 +2896,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.cmdenvironment())) + self.poutput('\nRead only settings:{}'.format(self._cmdenvironment())) else: self.perror("Parameter '{}' not supported (type 'set' for list of parameters).".format(param), traceback_war=False) @@ -2919,12 +2919,12 @@ class Cmd(cmd.Cmd): # Check if param was passed in if not args.param: - return self.show(args) + return self._show(args) param = utils.norm_fold(args.param.strip()) # Check if value was passed in if not args.value: - return self.show(args, param) + return self._show(args, param) value = args.value # Check if param points to just one settable @@ -2933,7 +2933,7 @@ class Cmd(cmd.Cmd): if len(hits) == 1: param = hits[0] else: - return self.show(args, param) + return self._show(args, param) # Update the settable's value current_value = getattr(self, param) @@ -3700,7 +3700,7 @@ class Cmd(cmd.Cmd): # _relative_load has been deprecated do__relative_load = do__relative_run_script - def run_transcript_tests(self, transcript_paths: List[str]) -> None: + def _run_transcript_tests(self, transcript_paths: List[str]) -> None: """Runs transcript tests for provided file(s). This is called when either -t is provided on the command line or the transcript_files argument is provided @@ -4020,7 +4020,7 @@ class Cmd(cmd.Cmd): # If transcript-based regression testing was requested, then do that instead of the main loop if self._transcript_files is not None: - self.run_transcript_tests([os.path.expanduser(tf) for tf in self._transcript_files]) + self._run_transcript_tests([os.path.expanduser(tf) for tf in self._transcript_files]) else: # If an intro was supplied in the method call, allow it to override the default if intro is not None: -- cgit v1.2.1 From d68b3feb3095ec717655972c5e4dc89d7c1ed579 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 15 Jun 2019 16:03:26 -0400 Subject: Updated CHANGELOG and made some more methods protected --- cmd2/cmd2.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 4e7a7a5d..3aa0895a 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1516,7 +1516,7 @@ class Cmd(cmd.Cmd): else: # Complete token against anything a user can run self._completion_matches = self.basic_complete(text, line, begidx, endidx, - self.get_commands_aliases_and_macros_for_completion()) + self._get_commands_aliases_and_macros_for_completion()) # Handle single result if len(self._completion_matches) == 1: @@ -1593,23 +1593,23 @@ class Cmd(cmd.Cmd): return commands - def get_alias_names(self) -> List[str]: + def _get_alias_names(self) -> List[str]: """Return list of current alias names""" return list(self.aliases) - def get_macro_names(self) -> List[str]: + def _get_macro_names(self) -> List[str]: """Return list of current macro names""" return list(self.macros) - def get_settable_names(self) -> List[str]: + def _get_settable_names(self) -> List[str]: """Return list of current settable names""" return list(self.settable) - def get_commands_aliases_and_macros_for_completion(self) -> List[str]: + def _get_commands_aliases_and_macros_for_completion(self) -> List[str]: """Return a list of visible commands, aliases, and macros for tab completion""" visible_commands = set(self.get_visible_commands()) - alias_names = set(self.get_alias_names()) - macro_names = set(self.get_macro_names()) + alias_names = set(self._get_alias_names()) + macro_names = set(self._get_macro_names()) return list(visible_commands | alias_names | macro_names) def get_help_topics(self) -> List[str]: @@ -2080,11 +2080,11 @@ class Cmd(cmd.Cmd): Get the function for a command :param command: the name of the command """ - func_name = self.cmd_func_name(command) + func_name = self._cmd_func_name(command) if func_name: return getattr(self, func_name) - def cmd_func_name(self, command: str) -> str: + def _cmd_func_name(self, command: str) -> str: """Get the method name associated with a given command. :param command: command to look up method name which implements it @@ -2346,7 +2346,7 @@ class Cmd(cmd.Cmd): epilog=alias_create_epilog) alias_create_parser.add_argument('name', help='name of this alias') setattr(alias_create_parser.add_argument('command', help='what the alias resolves to'), - ACTION_ARG_CHOICES, get_commands_aliases_and_macros_for_completion) + ACTION_ARG_CHOICES, _get_commands_aliases_and_macros_for_completion) setattr(alias_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command'), ACTION_ARG_CHOICES, ('path_complete',)) @@ -2358,7 +2358,7 @@ class Cmd(cmd.Cmd): alias_delete_parser = alias_subparsers.add_parser('delete', help=alias_delete_help, description=alias_delete_description) setattr(alias_delete_parser.add_argument('name', nargs='*', help='alias to delete'), - ACTION_ARG_CHOICES, get_alias_names) + ACTION_ARG_CHOICES, _get_alias_names) alias_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all aliases") alias_delete_parser.set_defaults(func=_alias_delete) @@ -2372,7 +2372,7 @@ class Cmd(cmd.Cmd): alias_list_parser = alias_subparsers.add_parser('list', help=alias_list_help, description=alias_list_description) setattr(alias_list_parser.add_argument('name', nargs="*", help='alias to list'), - ACTION_ARG_CHOICES, get_alias_names) + ACTION_ARG_CHOICES, _get_alias_names) alias_list_parser.set_defaults(func=_alias_list) # Preserve quotes since we are passing strings to other commands @@ -2550,7 +2550,7 @@ class Cmd(cmd.Cmd): epilog=macro_create_epilog) macro_create_parser.add_argument('name', help='name of this macro') setattr(macro_create_parser.add_argument('command', help='what the macro resolves to'), - ACTION_ARG_CHOICES, get_commands_aliases_and_macros_for_completion) + ACTION_ARG_CHOICES, _get_commands_aliases_and_macros_for_completion) setattr(macro_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command'), ACTION_ARG_CHOICES, ('path_complete',)) @@ -2562,7 +2562,7 @@ class Cmd(cmd.Cmd): macro_delete_parser = macro_subparsers.add_parser('delete', help=macro_delete_help, description=macro_delete_description) setattr(macro_delete_parser.add_argument('name', nargs='*', help='macro to delete'), - ACTION_ARG_CHOICES, get_macro_names) + ACTION_ARG_CHOICES, _get_macro_names) macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros") macro_delete_parser.set_defaults(func=_macro_delete) @@ -2575,7 +2575,7 @@ class Cmd(cmd.Cmd): macro_list_parser = macro_subparsers.add_parser('list', help=macro_list_help, description=macro_list_description) setattr(macro_list_parser.add_argument('name', nargs="*", help='macro to list'), - ACTION_ARG_CHOICES, get_macro_names) + ACTION_ARG_CHOICES, _get_macro_names) macro_list_parser.set_defaults(func=_macro_list) # Preserve quotes since we are passing strings to other commands @@ -2910,7 +2910,7 @@ class Cmd(cmd.Cmd): set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') setattr(set_parser.add_argument('param', nargs='?', help='parameter to set or view'), - ACTION_ARG_CHOICES, get_settable_names) + ACTION_ARG_CHOICES, _get_settable_names) set_parser.add_argument('value', nargs='?', help='the new value for settable') @with_argparser(set_parser) @@ -3908,7 +3908,7 @@ class Cmd(cmd.Cmd): # Restore the command and help functions to their original values dc = self.disabled_commands[command] - setattr(self, self.cmd_func_name(command), dc.command_function) + setattr(self, self._cmd_func_name(command), dc.command_function) if dc.help_function is None: delattr(self, help_func_name) @@ -3958,7 +3958,7 @@ class Cmd(cmd.Cmd): # Overwrite the command and help functions to print the message new_func = functools.partial(self._report_disabled_command_usage, message_to_print=message_to_print.replace(COMMAND_NAME, command)) - setattr(self, self.cmd_func_name(command), new_func) + setattr(self, self._cmd_func_name(command), new_func) setattr(self, help_func_name, new_func) def disable_category(self, category: str, message_to_print: str) -> None: -- cgit v1.2.1 From f77c44dd79b484f96a3077fd7ca64fd5b3c35fa1 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 15 Jun 2019 16:27:29 -0400 Subject: Fixed a few comments where "redirecting" accidentally got changed to "_redirecting" --- cmd2/cmd2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 3aa0895a..476edcaf 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -436,7 +436,7 @@ class Cmd(cmd.Cmd): # Used by complete() for readline tab completion self._completion_matches = [] - # Used to keep track of whether we are _redirecting or piping output + # Used to keep track of whether we are redirecting or piping output self._redirecting = False # Used to keep track of whether a continuation prompt is being displayed @@ -676,7 +676,7 @@ class Cmd(cmd.Cmd): if sys.platform.startswith('win') or os.environ.get('TERM') is not None: functional_terminal = True - # Don't attempt to use a pager that can block if _redirecting or running a script (either text or Python) + # Don't attempt to use a pager that can block if redirecting or running a script (either text or Python) # Also only attempt to use a pager if actually running in a real fully functional terminal if functional_terminal and not self._redirecting and not self._in_py and not self._script_dir: if self.colors.lower() == constants.COLORS_NEVER.lower(): -- cgit v1.2.1 From dd6f6b166c6929a778675c0b897ce5b8aa348e57 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sun, 16 Jun 2019 18:00:38 -0400 Subject: Started refactoring transcript testing to have a better display of information to the user --- cmd2/cmd2.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 476edcaf..f5a2b6fa 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -3708,7 +3708,10 @@ class Cmd(cmd.Cmd): :param transcript_paths: list of transcript test file paths """ + import time import unittest + import cmd2 + from colorama import Style from .transcript import Cmd2TestCase class TestMyAppCase(Cmd2TestCase): @@ -3721,15 +3724,28 @@ class Cmd(cmd.Cmd): self.exit_code = -1 return + verinfo = ".".join(map(str, sys.version_info[:3])) + num_transcripts = len(transcripts_expanded) + plural = '' if len(transcripts_expanded) == 1 else 's' + self.poutput(Style.BRIGHT + utils.center_text('cmd2 transcript test', pad='=') + Style.RESET_ALL) + self.poutput('platform {} -- Python {}, cmd2-{}, readline-{}'.format(sys.platform, verinfo, cmd2.__version__, + rl_type)) + self.poutput('cwd: {}'.format(os.getcwd())) + self.poutput('cmd2 app: {}'.format(sys.argv[0])) + self.poutput(Style.BRIGHT + 'collected {} transcript{}\n'.format(num_transcripts, plural) + Style.RESET_ALL) + self.__class__.testfiles = transcripts_expanded sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main() testcase = TestMyAppCase() stream = utils.StdSim(sys.stderr) runner = unittest.TextTestRunner(stream=stream) + start_time = time.time() test_results = runner.run(testcase) + execution_time = time.time() - start_time if test_results.wasSuccessful(): self._decolorized_write(sys.stderr, stream.read()) - self.poutput('Tests passed', color=Fore.LIGHTGREEN_EX) + finish_msg = '{0} transcript{1} passed in {2:.3f} seconds'.format(num_transcripts, plural, execution_time) + self.poutput(Style.BRIGHT + utils.center_text(finish_msg, pad='=') + Style.RESET_ALL, color=Fore.GREEN) else: # Strip off the initial traceback which isn't particularly useful for end users error_str = stream.read() -- cgit v1.2.1 From 181cecb217dd73056b72874d225e34528d484de8 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sun, 23 Jun 2019 20:38:17 -0400 Subject: Restored a few attributes to be public --- cmd2/cmd2.py | 102 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 51 insertions(+), 51 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index f5a2b6fa..6a518978 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -427,14 +427,14 @@ class Cmd(cmd.Cmd): self._script_dir = [] # Context manager used to protect critical sections in the main thread from stopping due to a KeyboardInterrupt - self._sigint_protection = utils.ContextFlag() + self.sigint_protection = utils.ContextFlag() # If the current command created a process to pipe to, then this will be a ProcReader object. # Otherwise it will be None. Its used to know when a pipe process can be killed and/or waited upon. self._cur_pipe_proc_reader = None # Used by complete() for readline tab completion - self._completion_matches = [] + self.completion_matches = [] # Used to keep track of whether we are redirecting or piping output self._redirecting = False @@ -537,7 +537,7 @@ class Cmd(cmd.Cmd): # This lock should be acquired before doing any asynchronous changes to the terminal to # ensure the updates to the terminal don't interfere with the input being typed or output # being printed by a command. - self._terminal_lock = threading.RLock() + self.terminal_lock = threading.RLock() # 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 @@ -688,7 +688,7 @@ class Cmd(cmd.Cmd): # Prevent KeyboardInterrupts while in the pager. The pager application will # still receive the SIGINT since it is in the same process group as us. - with self._sigint_protection: + with self.sigint_protection: pipe_proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE) pipe_proc.communicate(msg_str.encode('utf-8', 'replace')) else: @@ -1398,7 +1398,7 @@ class Cmd(cmd.Cmd): # Check if we either had a parsing error or are trying to complete the command token # The latter can happen if " or ' was entered as the command if len(tokens) <= 1: - self._completion_matches = [] + self.completion_matches = [] return None # Text we need to remove from completions later @@ -1456,20 +1456,20 @@ class Cmd(cmd.Cmd): # Attempt tab completion for redirection first, and if that isn't occurring, # call the completer function for the current command - self._completion_matches = self._redirect_complete(text, line, begidx, endidx, compfunc) + self.completion_matches = self._redirect_complete(text, line, begidx, endidx, compfunc) - if self._completion_matches: + if self.completion_matches: # Eliminate duplicates - self._completion_matches = utils.remove_duplicates(self._completion_matches) + self.completion_matches = utils.remove_duplicates(self.completion_matches) self.display_matches = utils.remove_duplicates(self.display_matches) if not self.display_matches: - # Since self.display_matches is empty, set it to self._completion_matches + # Since self.display_matches is empty, set it to self.completion_matches # before we alter them. That way the suggestions will reflect how we parsed # the token being completed and not how readline did. import copy - self.display_matches = copy.copy(self._completion_matches) + self.display_matches = copy.copy(self.completion_matches) # Check if we need to add an opening quote if not unclosed_quote: @@ -1477,7 +1477,7 @@ class Cmd(cmd.Cmd): add_quote = False # This is the tab completion text that will appear on the command line. - common_prefix = os.path.commonprefix(self._completion_matches) + common_prefix = os.path.commonprefix(self.completion_matches) if self.matches_delimited: # Check if any portion of the display matches appears in the tab completion @@ -1490,36 +1490,36 @@ class Cmd(cmd.Cmd): add_quote = True # If there is a tab completion and any match has a space, then add an opening quote - elif common_prefix and any(' ' in match for match in self._completion_matches): + elif common_prefix and any(' ' in match for match in self.completion_matches): add_quote = True if add_quote: # Figure out what kind of quote to add and save it as the unclosed_quote - if any('"' in match for match in self._completion_matches): + if any('"' in match for match in self.completion_matches): unclosed_quote = "'" else: unclosed_quote = '"' - self._completion_matches = [unclosed_quote + match for match in self._completion_matches] + self.completion_matches = [unclosed_quote + match for match in self.completion_matches] # Check if we need to remove text from the beginning of tab completions elif text_to_remove: - self._completion_matches = \ - [match.replace(text_to_remove, '', 1) for match in self._completion_matches] + self.completion_matches = \ + [match.replace(text_to_remove, '', 1) for match in self.completion_matches] # Check if we need to restore a shortcut in the tab completions # so it doesn't get erased from the command line if shortcut_to_restore: - self._completion_matches = \ - [shortcut_to_restore + match for match in self._completion_matches] + self.completion_matches = \ + [shortcut_to_restore + match for match in self.completion_matches] else: # Complete token against anything a user can run - self._completion_matches = self.basic_complete(text, line, begidx, endidx, - self._get_commands_aliases_and_macros_for_completion()) + self.completion_matches = self.basic_complete(text, line, begidx, endidx, + self._get_commands_aliases_and_macros_for_completion()) # Handle single result - if len(self._completion_matches) == 1: + if len(self.completion_matches) == 1: str_to_append = '' # Add a closing quote if needed and allowed @@ -1530,16 +1530,16 @@ class Cmd(cmd.Cmd): if self.allow_appended_space and endidx == len(line): str_to_append += ' ' - self._completion_matches[0] += str_to_append + self.completion_matches[0] += str_to_append # Sort matches if they haven't already been sorted if not self.matches_sorted: - self._completion_matches.sort(key=self.matches_sort_key) + self.completion_matches.sort(key=self.matches_sort_key) self.display_matches.sort(key=self.matches_sort_key) self.matches_sorted = True try: - return self._completion_matches[state] + return self.completion_matches[state] except IndexError: return None @@ -1631,7 +1631,7 @@ class Cmd(cmd.Cmd): self._cur_pipe_proc_reader.send_sigint() # Check if we are allowed to re-raise the KeyboardInterrupt - if not self._sigint_protection: + if not self.sigint_protection: raise KeyboardInterrupt("Got a keyboard interrupt") def precmd(self, statement: Statement) -> Statement: @@ -1700,7 +1700,7 @@ class Cmd(cmd.Cmd): try: # Get sigint protection while we set up redirection - with self._sigint_protection: + with self.sigint_protection: if pyscript_bridge_call: # Start saving command's stdout at this point self.stdout.pause_storage = False @@ -1743,7 +1743,7 @@ class Cmd(cmd.Cmd): self.pfeedback('Elapsed: {}'.format(datetime.datetime.now() - timestart)) finally: # Get sigint protection while we restore stuff - with self._sigint_protection: + with self.sigint_protection: if saved_state is not None: self._restore_output(statement, saved_state) @@ -1765,7 +1765,7 @@ class Cmd(cmd.Cmd): def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement]) -> bool: """Run the command finalization hooks""" - with self._sigint_protection: + with self.sigint_protection: if not sys.platform.startswith('win') and self.stdout.isatty(): # Before the next command runs, fix any terminal problems like those # caused by certain binary characters having been printed to it. @@ -2147,10 +2147,10 @@ class Cmd(cmd.Cmd): if self.use_rawinput: try: if sys.stdin.isatty(): - # Wrap in try since _terminal_lock may not be locked when this function is called from unit tests + # Wrap in try since terminal_lock may not be locked when this function is called from unit tests try: # A prompt is about to be drawn. Allow asynchronous changes to the terminal. - self._terminal_lock.release() + self.terminal_lock.release() except RuntimeError: pass @@ -2166,7 +2166,7 @@ class Cmd(cmd.Cmd): finally: if sys.stdin.isatty(): # The prompt is gone. Do not allow asynchronous changes to the terminal. - self._terminal_lock.acquire() + self.terminal_lock.acquire() else: if self.stdin.isatty(): # on a tty, print the prompt first, then read the line @@ -2970,7 +2970,7 @@ class Cmd(cmd.Cmd): # Prevent KeyboardInterrupts while in the shell process. The shell process will # still receive the SIGINT since it is in the same process group as us. - with self._sigint_protection: + with self.sigint_protection: # For any stream that is a StdSim, we will use a pipe so we can capture its output proc = subprocess.Popen(expanded_command, stdout=subprocess.PIPE if isinstance(self.stdout, utils.StdSim) else self.stdout, @@ -3490,7 +3490,7 @@ class Cmd(cmd.Cmd): commands_run = 0 try: - with self._sigint_protection: + with self.sigint_protection: # Disable echo while we manually redirect stdout to a StringIO buffer saved_echo = self.echo saved_stdout = self.stdout @@ -3535,7 +3535,7 @@ class Cmd(cmd.Cmd): if stop: break finally: - with self._sigint_protection: + with self.sigint_protection: # Restore altered attributes to their original state self.echo = saved_echo self.stdout = saved_stdout @@ -3655,7 +3655,7 @@ class Cmd(cmd.Cmd): return self.runcmds_plus_hooks(script_commands) finally: - with self._sigint_protection: + with self.sigint_protection: # Check if a script dir was added before an exception occurred if orig_script_dir_count != len(self._script_dir): self._script_dir.pop() @@ -3765,14 +3765,14 @@ class Cmd(cmd.Cmd): To the user it appears as if an alert message is printed above the prompt and their current input text and cursor location is left alone. - IMPORTANT: This function will not print an alert unless it can acquire self._terminal_lock to ensure + IMPORTANT: This function will not print an alert unless it can acquire self.terminal_lock to ensure a prompt is onscreen. Therefore it is best to acquire the lock before calling this function to guarantee the alert prints. :param alert_msg: the message to display to the user :param new_prompt: if you also want to change the prompt that is displayed, then include it here see async_update_prompt() docstring for guidance on updating a prompt - :raises RuntimeError if called while another thread holds _terminal_lock + :raises RuntimeError if called while another thread holds terminal_lock """ if not (vt100_support and self.use_rawinput): return @@ -3781,8 +3781,8 @@ class Cmd(cmd.Cmd): import colorama.ansi as ansi from colorama import Cursor - # Sanity check that can't fail if self._terminal_lock was acquired before calling this function - if self._terminal_lock.acquire(blocking=False): + # Sanity check that can't fail if self.terminal_lock was acquired before calling this function + if self.terminal_lock.acquire(blocking=False): # Figure out what prompt is displaying current_prompt = self.continuation_prompt if self._at_continuation_prompt else self.prompt @@ -3857,10 +3857,10 @@ class Cmd(cmd.Cmd): # Redraw the prompt and input lines rl_force_redisplay() - self._terminal_lock.release() + self.terminal_lock.release() else: - raise RuntimeError("another thread holds _terminal_lock") + raise RuntimeError("another thread holds terminal_lock") def async_update_prompt(self, new_prompt: str) -> None: # pragma: no cover """ @@ -3870,7 +3870,7 @@ class Cmd(cmd.Cmd): it is best to keep the prompt the same width as what's on screen. Otherwise the user's input text will be shifted and the update will not be seamless. - IMPORTANT: This function will not update the prompt unless it can acquire self._terminal_lock to ensure + IMPORTANT: This function will not update the prompt unless it can acquire self.terminal_lock to ensure a prompt is onscreen. Therefore it is best to acquire the lock before calling this function to guarantee the prompt changes. @@ -3879,7 +3879,7 @@ class Cmd(cmd.Cmd): and display immediately after the multiline line command completes. :param new_prompt: what to change the prompt to - :raises RuntimeError if called while another thread holds _terminal_lock + :raises RuntimeError if called while another thread holds terminal_lock """ self.async_alert('', new_prompt) @@ -3887,18 +3887,18 @@ class Cmd(cmd.Cmd): """ Set the terminal window title - IMPORTANT: This function will not set the title unless it can acquire self._terminal_lock to avoid + IMPORTANT: This function will not set the title unless it can acquire self.terminal_lock to avoid writing to stderr while a command is running. Therefore it is best to acquire the lock before calling this function to guarantee the title changes. :param title: the new window title - :raises RuntimeError if called while another thread holds _terminal_lock + :raises RuntimeError if called while another thread holds terminal_lock """ if not vt100_support: return - # Sanity check that can't fail if self._terminal_lock was acquired before calling this function - if self._terminal_lock.acquire(blocking=False): + # Sanity check that can't fail if self.terminal_lock was acquired before calling this function + if self.terminal_lock.acquire(blocking=False): try: import colorama.ansi as ansi sys.stderr.write(ansi.set_title(title)) @@ -3906,10 +3906,10 @@ class Cmd(cmd.Cmd): # Debugging in Pycharm has issues with setting terminal title pass finally: - self._terminal_lock.release() + self.terminal_lock.release() else: - raise RuntimeError("another thread holds _terminal_lock") + raise RuntimeError("another thread holds terminal_lock") def enable_command(self, command: str) -> None: """ @@ -4027,7 +4027,7 @@ class Cmd(cmd.Cmd): signal.signal(signal.SIGINT, self.sigint_handler) # Grab terminal lock before the prompt has been drawn by readline - self._terminal_lock.acquire() + self.terminal_lock.acquire() # Always run the preloop first for func in self._preloop_hooks: @@ -4056,7 +4056,7 @@ class Cmd(cmd.Cmd): # Release terminal lock now that postloop code should have stopped any terminal updater threads # This will also zero the lock count in case cmdloop() is called again - self._terminal_lock.release() + self.terminal_lock.release() # Restore the original signal handler signal.signal(signal.SIGINT, original_sigint_handler) -- cgit v1.2.1 From 652122f3c9907a652a9c3a14581bb2aef90bc996 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sun, 23 Jun 2019 20:49:27 -0400 Subject: Made last_result public and restored the initialization of it in __init__ and associated comment --- cmd2/cmd2.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 6a518978..d44e6df4 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -423,6 +423,10 @@ class Cmd(cmd.Cmd): # True if running inside a Python script or interactive console, False otherwise self._in_py = False + # Stores results from the last command run to enable usage of results in a Python script or interactive console + # Built-in commands don't make use of this. It is purely there for user-defined commands and convenience. + self.last_result = None + # Used by run_script command to store current script dir as a LIFO queue to support _relative_run_script command self._script_dir = [] -- cgit v1.2.1 From eb1936e568a2ca4817ab0cd640220a5bc355e226 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sun, 23 Jun 2019 21:03:04 -0400 Subject: Made tokens_for_completion() method public since a couple of our examples use it --- cmd2/cmd2.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index d44e6df4..e5c2ac44 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -724,7 +724,7 @@ class Cmd(cmd.Cmd): # 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]]: + def tokens_for_completion(self, line: str, begidx: int, endidx: int) -> Tuple[List[str], List[str]]: """ Used by tab completion functions to get all tokens through the one being completed :param line: the current input line with leading whitespace removed @@ -938,7 +938,7 @@ class Cmd(cmd.Cmd): :return: a list of possible tab completions """ # Get all tokens through the one being completed - tokens, _ = self._tokens_for_completion(line, begidx, endidx) + tokens, _ = self.tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -980,7 +980,7 @@ class Cmd(cmd.Cmd): :return: a list of possible tab completions """ # Get all tokens through the one being completed - tokens, _ = self._tokens_for_completion(line, begidx, endidx) + tokens, _ = self.tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -1192,7 +1192,7 @@ class Cmd(cmd.Cmd): # Get all tokens through the one being completed. We want the raw tokens # so we can tell if redirection strings are quoted and ignore them. - _, raw_tokens = self._tokens_for_completion(line, begidx, endidx) + _, raw_tokens = self.tokens_for_completion(line, begidx, endidx) if not raw_tokens: return [] @@ -1397,7 +1397,7 @@ class Cmd(cmd.Cmd): line = expanded_line # Get all tokens through the one being completed - tokens, raw_tokens = self._tokens_for_completion(line, begidx, endidx) + tokens, raw_tokens = self.tokens_for_completion(line, begidx, endidx) # Check if we either had a parsing error or are trying to complete the command token # The latter can happen if " or ' was entered as the command @@ -1570,7 +1570,7 @@ class Cmd(cmd.Cmd): """Default completion function for argparse commands.""" completer = AutoCompleter(argparser, self) - tokens, _ = self._tokens_for_completion(line, begidx, endidx) + tokens, _ = self.tokens_for_completion(line, begidx, endidx) if not tokens: return [] @@ -2607,7 +2607,7 @@ class Cmd(cmd.Cmd): """Completes the subcommand argument of help""" # Get all tokens through the one being completed - tokens, _ = self._tokens_for_completion(line, begidx, endidx) + tokens, _ = self.tokens_for_completion(line, begidx, endidx) if not tokens: return [] -- cgit v1.2.1