summaryrefslogtreecommitdiff
path: root/cmd2
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2018-05-17 18:08:52 -0400
committerEric Lin <anselor@gmail.com>2018-05-17 18:08:52 -0400
commitff89bad1b0dd2a608081db5a8fa299ef43d66bc5 (patch)
tree5b5ba5f355d4026e563af3491ee6758642833f10 /cmd2
parent371284d20370a8e85dd8527d9bbcc6267b335cde (diff)
downloadcmd2-git-ff89bad1b0dd2a608081db5a8fa299ef43d66bc5.tar.gz
Suppresses stdout and stderr output by default when calling an application command from pyscript.
Added support for tab completing application commands in ipython shell Updated unit tests scripts to set cmd_echo to True to validate command output.
Diffstat (limited to 'cmd2')
-rw-r--r--cmd2/pyscript_bridge.py46
1 files changed, 31 insertions, 15 deletions
diff --git a/cmd2/pyscript_bridge.py b/cmd2/pyscript_bridge.py
index ecd2b622..a1c367e2 100644
--- a/cmd2/pyscript_bridge.py
+++ b/cmd2/pyscript_bridge.py
@@ -41,13 +41,15 @@ class CommandResult(namedtuple_with_defaults('CmdResult', ['stdout', 'stderr', '
class CopyStream(object):
"""Copies all data written to a stream"""
- def __init__(self, inner_stream):
+ def __init__(self, inner_stream, echo):
self.buffer = ''
self.inner_stream = inner_stream
+ self.echo = echo
def write(self, s):
self.buffer += s
- self.inner_stream.write(s)
+ if self.echo:
+ self.inner_stream.write(s)
def read(self):
raise NotImplementedError
@@ -62,12 +64,12 @@ class CopyStream(object):
return getattr(self.inner_stream, item)
-def _exec_cmd(cmd2_app, func):
+def _exec_cmd(cmd2_app, func, echo):
"""Helper to encapsulate executing a command and capturing the results"""
- copy_stdout = CopyStream(sys.stdout)
- copy_stderr = CopyStream(sys.stderr)
+ copy_stdout = CopyStream(sys.stdout, echo)
+ copy_stderr = CopyStream(sys.stderr, echo)
- copy_cmd_stdout = CopyStream(cmd2_app.stdout)
+ copy_cmd_stdout = CopyStream(cmd2_app.stdout, echo)
cmd2_app._last_result = None
@@ -80,7 +82,7 @@ def _exec_cmd(cmd2_app, func):
cmd2_app.stdout = copy_cmd_stdout.inner_stream
# if stderr is empty, set it to None
- stderr = copy_stderr if copy_stderr.buffer else None
+ stderr = copy_stderr.buffer if copy_stderr.buffer else None
outbuf = copy_cmd_stdout.buffer if copy_cmd_stdout.buffer else copy_stdout.buffer
result = CommandResult(stdout=outbuf, stderr=stderr, data=cmd2_app._last_result)
@@ -91,7 +93,8 @@ class ArgparseFunctor:
"""
Encapsulates translating python object traversal
"""
- def __init__(self, cmd2_app, item, parser):
+ def __init__(self, echo: bool, cmd2_app, item, parser):
+ self._echo = echo
self._cmd2_app = cmd2_app
self._item = item
self._parser = parser
@@ -101,6 +104,14 @@ class ArgparseFunctor:
# argparse object for the current command layer
self.__current_subcommand_parser = parser
+ def __dir__(self):
+ """Returns a custom list of attribute names to match the sub-commands"""
+ commands = []
+ for action in self.__current_subcommand_parser._actions:
+ if not action.option_strings and isinstance(action, argparse._SubParsersAction):
+ commands.extend(action.choices)
+ return commands
+
def __getattr__(self, item):
"""Search for a subcommand matching this item and update internal state to track the traversal"""
# look for sub-command under the current command/sub-command layer
@@ -114,7 +125,6 @@ class ArgparseFunctor:
return self
raise AttributeError(item)
- # return super().__getattr__(item)
def __call__(self, *args, **kwargs):
"""
@@ -251,9 +261,8 @@ class ArgparseFunctor:
traverse_parser(self._parser)
- # print('Command: {}'.format(cmd_str[0]))
+ return _exec_cmd(self._cmd2_app, functools.partial(func, cmd_str[0]), self._echo)
- return _exec_cmd(self._cmd2_app, functools.partial(func, cmd_str[0]))
class PyscriptBridge(object):
"""Preserves the legacy 'cmd' interface for pyscript while also providing a new python API wrapper for
@@ -261,6 +270,7 @@ class PyscriptBridge(object):
def __init__(self, cmd2_app):
self._cmd2_app = cmd2_app
self._last_result = None
+ self.cmd_echo = False
def __getattr__(self, item: str):
"""Check if the attribute is a command. If so, return a callable."""
@@ -274,13 +284,19 @@ class PyscriptBridge(object):
except AttributeError:
# Command doesn't, 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))
+ return _exec_cmd(self._cmd2_app, functools.partial(func, args), self.cmd_echo)
return wrap_func
else:
# Command does use argparse, return an object that can traverse the argparse subcommands and arguments
- return ArgparseFunctor(self._cmd2_app, item, parser)
+ return ArgparseFunctor(self.cmd_echo, self._cmd2_app, item, parser)
- raise AttributeError(item)
+ return super().__getattr__(item)
+
+ def __dir__(self):
+ """Return a custom set of attribute names to match the available commands"""
+ commands = list(self._cmd2_app.get_all_commands())
+ commands.insert(0, 'cmd_echo')
+ return commands
def __call__(self, args):
- return _exec_cmd(self._cmd2_app, functools.partial(self._cmd2_app.onecmd_plus_hooks, args + '\n'))
+ return _exec_cmd(self._cmd2_app, functools.partial(self._cmd2_app.onecmd_plus_hooks, args + '\n'), self.cmd_echo)