diff options
Diffstat (limited to 'cmd2/cmd2.py')
-rw-r--r-- | cmd2/cmd2.py | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index dbdb55ef..3083900d 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -164,8 +164,10 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> return cmd_wrapper if len(args) == 1 and callable(args[0]): + # noinspection PyTypeChecker return arg_decorator(args[0]) else: + # noinspection PyTypeChecker return arg_decorator @@ -188,7 +190,6 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *, """ import functools - # noinspection PyProtectedMember def arg_decorator(func: Callable): @functools.wraps(func) def cmd_wrapper(cmd2_app, statement: Union[Statement, str]): @@ -226,6 +227,7 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *, return cmd_wrapper + # noinspection PyTypeChecker return arg_decorator @@ -246,7 +248,6 @@ def with_argparser(argparser: argparse.ArgumentParser, *, """ import functools - # noinspection PyProtectedMember def arg_decorator(func: Callable): @functools.wraps(func) def cmd_wrapper(cmd2_app, statement: Union[Statement, str]): @@ -284,6 +285,7 @@ def with_argparser(argparser: argparse.ArgumentParser, *, return cmd_wrapper + # noinspection PyTypeChecker return arg_decorator @@ -427,14 +429,14 @@ class Cmd(cmd.Cmd): # Defines app-specific variables/functions available in Python shells and pyscripts self.py_locals = {} + # True if running inside a Python script or interactive console, False otherwise + self._in_py = False + 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 @@ -1724,10 +1726,13 @@ class Cmd(cmd.Cmd): statement = self.statement_parser.parse_command_only(line) return statement.command, statement.args, statement.command_and_args - def onecmd_plus_hooks(self, line: str, *, add_to_history: bool = True, py_bridge_call: bool = False) -> bool: + def onecmd_plus_hooks(self, line: str, *, expand: bool = True, add_to_history: bool = True, + py_bridge_call: bool = False) -> bool: """Top-level function called by cmdloop() to handle parsing a line and running the command and all of its hooks. - :param line: line of text read from input + :param line: command line to run + :param expand: If True, then aliases, macros, and shortcuts will be expanded. + Set this to False if the command line should not be altered. :param add_to_history: If True, then add this command to history. Defaults to True. :param py_bridge_call: This should only ever be set to True by PyBridge to signify the beginning of an app() call from Python. It is used to enable/disable the storage of the @@ -1738,7 +1743,7 @@ class Cmd(cmd.Cmd): stop = False try: - statement = self._input_line_to_statement(line) + statement = self._input_line_to_statement(line, expand=expand) except EmptyStatement: return self._run_cmdfinalization_hooks(stop, None) except ValueError as ex: @@ -1853,12 +1858,15 @@ class Cmd(cmd.Cmd): except Exception as ex: self.pexcept(ex) - def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]], *, add_to_history: bool = True) -> bool: + def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]], *, + expand: bool = True, add_to_history: bool = True) -> bool: """ Used when commands are being run in an automated fashion like text scripts or history replays. The prompt and command line for each command will be printed if echo is True. :param cmds: commands to run + :param expand: If True, then aliases, macros, and shortcuts will be expanded. + Set this to False if the command line should not be altered. :param add_to_history: If True, then add these commands to history. Defaults to True. :return: True if running of commands should stop """ @@ -1869,12 +1877,12 @@ class Cmd(cmd.Cmd): if self.echo: self.poutput('{}{}'.format(self.prompt, line)) - if self.onecmd_plus_hooks(line, add_to_history=add_to_history): + if self.onecmd_plus_hooks(line, expand=expand, add_to_history=add_to_history): return True return False - def _complete_statement(self, line: str) -> Statement: + def _complete_statement(self, line: str, *, expand: bool = True) -> Statement: """Keep accepting lines of input until the command is complete. There is some pretty hacky code here to handle some quirks of @@ -1883,11 +1891,13 @@ class Cmd(cmd.Cmd): backwards compatibility with the standard library version of cmd. :param line: the line being parsed + :param expand: If True, then aliases, macros, and shortcuts will be expanded. + Set this to False if the command line should not be altered. :return: the completed Statement """ while True: try: - statement = self.statement_parser.parse(line) + statement = self.statement_parser.parse(line, expand=expand) if statement.multiline_command and statement.terminator: # we have a completed multiline command, we are done break @@ -1898,7 +1908,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, expand=expand) if not statement.multiline_command: # not a multiline command, so raise the exception raise @@ -1935,11 +1945,13 @@ class Cmd(cmd.Cmd): raise EmptyStatement() return statement - def _input_line_to_statement(self, line: str) -> Statement: + def _input_line_to_statement(self, line: str, *, expand: bool = True) -> Statement: """ Parse the user's input line and convert it to a Statement, ensuring that all macros are also resolved :param line: the line being parsed + :param expand: If True, then aliases, macros, and shortcuts will be expanded. + Set this to False if the command line should not be altered. :return: parsed command line as a Statement """ used_macros = [] @@ -1948,14 +1960,14 @@ class Cmd(cmd.Cmd): # Continue until all macros are resolved while True: # Make sure all input has been read and convert it to a Statement - statement = self._complete_statement(line) + statement = self._complete_statement(line, expand=expand) # Save the fully entered line if this is the first loop iteration if orig_line is None: orig_line = statement.raw # Check if this command matches a macro and wasn't already processed to avoid an infinite loop - if statement.command in self.macros.keys() and statement.command not in used_macros: + if expand and statement.command in self.macros.keys() and statement.command not in used_macros: used_macros.append(statement.command) line = self._resolve_macro(statement) if line is None: @@ -2170,19 +2182,22 @@ class Cmd(cmd.Cmd): return target if callable(getattr(self, target, None)) else '' # noinspection PyMethodOverriding - def onecmd(self, statement: Union[Statement, str], *, add_to_history: bool = True) -> bool: + def onecmd(self, statement: Union[Statement, str], *, + expand: bool = True, add_to_history: bool = True) -> bool: """ This executes the actual do_* method for a command. If the command provided doesn't exist, then it executes default() instead. :param statement: intended to be a Statement instance parsed command from the input stream, alternative acceptance of a str is present only for backward compatibility with cmd + :param expand: If True, then aliases, macros, and shortcuts will be expanded. + Set this to False if the command line should not be altered. :param add_to_history: If True, then add this command to history. Defaults to True. :return: a flag indicating whether the interpretation of commands should stop """ # For backwards compatibility with cmd, allow a str to be passed in if not isinstance(statement, Statement): - statement = self._input_line_to_statement(statement) + statement = self._input_line_to_statement(statement, expand=expand) func = self.cmd_func(statement.command) if func: @@ -3858,6 +3873,7 @@ class Cmd(cmd.Cmd): sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main() testcase = TestMyAppCase() stream = utils.StdSim(sys.stderr) + # noinspection PyTypeChecker runner = unittest.TextTestRunner(stream=stream) start_time = time.time() test_results = runner.run(testcase) |