summaryrefslogtreecommitdiff
path: root/cmd2/pyscript_bridge.py
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2018-05-02 11:22:10 -0400
committerEric Lin <anselor@gmail.com>2018-05-02 11:22:10 -0400
commit2528fb5217063a5a98f7ea2b880bfc75e7f2428c (patch)
treebfa1d30d5a2e1cebeffac4ea8d867588105b79a9 /cmd2/pyscript_bridge.py
parentbf5288829afde976dd213d15aa37704c3eb0a087 (diff)
downloadcmd2-git-2528fb5217063a5a98f7ea2b880bfc75e7f2428c.tar.gz
Added support for customizing the pyscript bridge pystate object name.
Removed all legacy pystate objects. Changed default behavior to clear _last_result before each command Added utility for creating named tuples with default values Added tests to exercise new changes.
Diffstat (limited to 'cmd2/pyscript_bridge.py')
-rw-r--r--cmd2/pyscript_bridge.py60
1 files changed, 41 insertions, 19 deletions
diff --git a/cmd2/pyscript_bridge.py b/cmd2/pyscript_bridge.py
index bf64f50d..055ae4ae 100644
--- a/cmd2/pyscript_bridge.py
+++ b/cmd2/pyscript_bridge.py
@@ -9,6 +9,7 @@ Released under MIT license, see LICENSE file
import argparse
from collections import namedtuple
+import functools
import sys
from typing import List, Tuple
@@ -19,27 +20,58 @@ else:
from contextlib import redirect_stdout, redirect_stderr
from .argparse_completer import _RangeAction
+from .utils import namedtuple_with_defaults
-CommandResult = namedtuple('FunctionResult', 'stdout stderr data')
+class CommandResult(namedtuple_with_defaults('CmdResult', ['stdout', 'stderr', 'data'])):
+ """Encapsulates the results from a command.
+
+ Named tuple attributes
+ ----------------------
+ stdout: str - Output captured from stdout while this command is executing
+ stderr: str - Output captured from stderr while this command is executing. None if no error captured
+ data - Data returned by the command.
+
+ NOTE: Named tuples are immutable. So the contents are there for access, not for modification.
+ """
+ def __bool__(self):
+ """If stderr is None and data is not None the command is considered a success"""
+ return not self.stderr and self.data is not None
class CopyStream(object):
- """ Toy class for replacing self.stdout in cmd2.Cmd instances for unit testing. """
- def __init__(self, innerStream):
+ """Copies all data written to a stream"""
+ def __init__(self, inner_stream):
self.buffer = ''
- self.innerStream = innerStream
+ self.inner_stream = inner_stream
def write(self, s):
self.buffer += s
- self.innerStream.write(s)
+ self.inner_stream.write(s)
def read(self):
raise NotImplementedError
def clear(self):
self.buffer = ''
- self.innerStream.clear()
+
+
+def _exec_cmd(cmd2_app, func):
+ """Helper to encapsulate executing a command and capturing the results"""
+ copy_stdout = CopyStream(sys.stdout)
+ copy_stderr = CopyStream(sys.stderr)
+
+ cmd2_app._last_result = None
+
+ with redirect_stdout(copy_stdout):
+ with redirect_stderr(copy_stderr):
+ func()
+
+ # if stderr is empty, set it to None
+ stderr = copy_stderr if copy_stderr.buffer else None
+
+ result = CommandResult(stdout=copy_stdout.buffer, stderr=stderr, data=cmd2_app._last_result)
+ return result
class ArgparseFunctor:
@@ -208,14 +240,7 @@ class ArgparseFunctor:
# print('Command: {}'.format(cmd_str[0]))
- copyStdOut = CopyStream(sys.stdout)
- copyStdErr = CopyStream(sys.stderr)
- with redirect_stdout(copyStdOut):
- with redirect_stderr(copyStdErr):
- func(cmd_str[0])
- result = CommandResult(stdout=copyStdOut.buffer, stderr=copyStdErr.buffer, data=self._cmd2_app._last_result)
- return result
-
+ 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
@@ -236,8 +261,7 @@ class PyscriptBridge(object):
except AttributeError:
# Command doesn't, we will accept parameters in the form of a command string
def wrap_func(args=''):
- func(args)
- return self._cmd2_app._last_result
+ return _exec_cmd(self._cmd2_app, functools.partial(func, args))
return wrap_func
else:
# Command does use argparse, return an object that can traverse the argparse subcommands and arguments
@@ -246,6 +270,4 @@ class PyscriptBridge(object):
raise AttributeError(item)
def __call__(self, args):
- self._cmd2_app.onecmd_plus_hooks(args + '\n')
- self._last_result = self._cmd2_app._last_result
- return self._cmd2_app._last_result
+ return _exec_cmd(self._cmd2_app, functools.partial(self._cmd2_app.onecmd_plus_hooks, args + '\n'))