diff options
author | kmvanbrunt <kmvanbrunt@gmail.com> | 2018-10-13 18:23:10 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-13 18:23:10 -0400 |
commit | dcb5be4216e0ac42a995ffe74a7ea712072caea1 (patch) | |
tree | c888ddd5e49ef1f8d8e9552bf93e3d6fda1c382b | |
parent | 3dcff6406ff772678d2e003a0fd56c5a64d39e60 (diff) | |
parent | be82ee5d66f18343cc055b1daf84a0b14454eec7 (diff) | |
download | cmd2-git-dcb5be4216e0ac42a995ffe74a7ea712072caea1.tar.gz |
Merge pull request #578 from python-cmd2/func_plus_hooks0.9.6
Func plus hooks
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | CHANGELOG.md | 6 | ||||
-rw-r--r-- | cmd2/pyscript_bridge.py | 53 |
3 files changed, 37 insertions, 27 deletions
@@ -26,8 +26,5 @@ htmlcov dmypy.json dmypy.sock -# cmd2 history file used in main.py +# cmd2 history file used in hello_cmd2.py cmd2_history.txt - -# Virtual environment -venv diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8affab..0b33bd1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,11 @@ -## 0.9.6 (TBD) +## 0.9.6 (October 13, 2018) +* Bug Fixes + * Fixed bug introduced in 0.9.5 caused by backing up and restoring `self.prompt` in `pseudo_raw_input`. + As part of this fix, continuation prompts will not be redrawn with `async_update_prompt` or `async_alert`. * Enhancements * All platforms now depend on [wcwidth](https://pypi.python.org/pypi/wcwidth) to assist with asynchronous alerts. * Macros now accept extra arguments when called. These will be tacked onto the resolved command. + * All cmd2 commands run via py now go through onecmd_plus_hooks. ## 0.9.5 (October 11, 2018) * Bug Fixes diff --git a/cmd2/pyscript_bridge.py b/cmd2/pyscript_bridge.py index 3c5c61f2..7551ed88 100644 --- a/cmd2/pyscript_bridge.py +++ b/cmd2/pyscript_bridge.py @@ -45,8 +45,14 @@ class CommandResult(namedtuple_with_defaults('CommandResult', ['stdout', 'stderr return not self.stderr -def _exec_cmd(cmd2_app, func: Callable, echo: bool) -> CommandResult: - """Helper to encapsulate executing a command and capturing the results""" +def _exec_cmd(cmd2_app, command: str, echo: bool) -> CommandResult: + """ + Helper to encapsulate executing a command and capturing the results + :param cmd2_app: cmd2 app that will run the command + :param command: command line being run + :param echo: if True, output will be echoed to stdout/stderr while the command runs + :return: result of the command + """ copy_stdout = StdSim(sys.stdout, echo) copy_stderr = StdSim(sys.stderr, echo) @@ -58,7 +64,8 @@ def _exec_cmd(cmd2_app, func: Callable, echo: bool) -> CommandResult: cmd2_app.stdout = copy_cmd_stdout with redirect_stdout(copy_stdout): with redirect_stderr(copy_stderr): - func() + # Include a newline in case it's a multiline command + cmd2_app.onecmd_plus_hooks(command + '\n') finally: cmd2_app.stdout = copy_cmd_stdout.inner_stream @@ -199,20 +206,21 @@ class ArgparseFunctor: self._command_name)) # reconstruct the cmd2 command from the python call - cmd_str = [''] + command = self._command_name def process_argument(action, value): + nonlocal command if isinstance(action, argparse._CountAction): if isinstance(value, int): for _ in range(value): - cmd_str[0] += '{} '.format(action.option_strings[0]) + command += ' {}'.format(action.option_strings[0]) return else: raise TypeError('Expected int for ' + action.dest) if isinstance(action, argparse._StoreConstAction) or isinstance(action, argparse._AppendConstAction): if value: # Nothing else to append to the command string, just the flag is enough. - cmd_str[0] += '{} '.format(action.option_strings[0]) + command += ' {}'.format(action.option_strings[0]) return else: # value is not True so we default to false, which means don't include the flag @@ -220,7 +228,7 @@ class ArgparseFunctor: # was the argument a flag? if action.option_strings: - cmd_str[0] += '{} '.format(action.option_strings[0]) + command += ' {}'.format(action.option_strings[0]) is_remainder_arg = action.dest == self._remainder_arg @@ -231,14 +239,14 @@ class ArgparseFunctor: raise ValueError('{} appears to be a flag and should be supplied as a keyword argument ' 'to the function.'.format(item)) item = quote_string_if_needed(item) - cmd_str[0] += '{} '.format(item) + command += ' {}'.format(item) # If this is a flag parameter that can accept a variable number of arguments and we have not # reached the max number, add a list completion suffix to tell argparse to move to the next # parameter if action.option_strings and isinstance(action, _RangeAction) and action.nargs_max is not None and \ action.nargs_max > len(value): - cmd_str[0] += '{0}{0} '.format(self._parser.prefix_chars[0]) + command += ' {0}{0}'.format(self._parser.prefix_chars[0]) else: value = str(value).strip() @@ -246,18 +254,19 @@ class ArgparseFunctor: raise ValueError('{} appears to be a flag and should be supplied as a keyword argument ' 'to the function.'.format(value)) value = quote_string_if_needed(value) - cmd_str[0] += '{} '.format(value) + command += ' {}'.format(value) # If this is a flag parameter that can accept a variable number of arguments and we have not # reached the max number, add a list completion suffix to tell argparse to move to the next # parameter if action.option_strings and isinstance(action, _RangeAction) and action.nargs_max is not None and \ action.nargs_max > 1: - cmd_str[0] += '{0}{0} '.format(self._parser.prefix_chars[0]) + command += ' {0}{0}'.format(self._parser.prefix_chars[0]) def process_action(action): + nonlocal command if isinstance(action, argparse._SubParsersAction): - cmd_str[0] += '{} '.format(self._args[action.dest]) + command += ' {}'.format(self._args[action.dest]) traverse_parser(action.choices[self._args[action.dest]]) elif isinstance(action, argparse._AppendAction): if isinstance(self._args[action.dest], list) or isinstance(self._args[action.dest], tuple): @@ -284,8 +293,7 @@ class ArgparseFunctor: process_action(action) traverse_parser(self._parser) - - return _exec_cmd(self._cmd2_app, functools.partial(func, cmd_str[0]), self._echo) + return _exec_cmd(self._cmd2_app, command, self._echo) class PyscriptBridge(object): @@ -310,7 +318,10 @@ class PyscriptBridge(object): else: # Command doesn't use argparse, we will accept parameters in the form of a command string def wrap_func(args=''): - return _exec_cmd(self._cmd2_app, functools.partial(func, args), self.cmd_echo) + command = item + if args: + command += ' ' + args + return _exec_cmd(self._cmd2_app, command, self.cmd_echo) return wrap_func else: @@ -323,17 +334,15 @@ class PyscriptBridge(object): attributes.insert(0, 'cmd_echo') return attributes - def __call__(self, args: str, echo: Optional[bool]=None) -> CommandResult: + def __call__(self, command: str, echo: Optional[bool]=None) -> CommandResult: """ Provide functionality to call application commands by calling PyscriptBridge ex: app('help') - :param args: The string being passed to the command - :param echo: If True, output will be echoed while the command runs - This temporarily overrides the value of self.cmd_echo + :param command: command line being run + :param echo: if True, output will be echoed to stdout/stderr while the command runs + this temporarily overrides the value of self.cmd_echo """ if echo is None: echo = self.cmd_echo - return _exec_cmd(self._cmd2_app, - functools.partial(self._cmd2_app.onecmd_plus_hooks, args + '\n'), - echo) + return _exec_cmd(self._cmd2_app, command, echo) |