commit ae48d813dafcae8f46f50d35b758dd5287d178cf Author: Damian Johnson atagar@torproject.org Date: Sun Jul 31 15:59:47 2016 -0700
Don't use stdout/stderr directly for python output
Python interpreter commands use the builtin InteactiveConsole which interacts with stdout and stderr directly. This isn't a problem for our tor-prompt since it writes to stdout anyway, but it breaks nyx.
Nicest option I've found for this is...
https://stackoverflow.com/questions/13250050/redirecting-the-output-of-a-pyt... --- stem/interpreter/commands.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/stem/interpreter/commands.py b/stem/interpreter/commands.py index 82a216d..e348c6e 100644 --- a/stem/interpreter/commands.py +++ b/stem/interpreter/commands.py @@ -6,7 +6,9 @@ Handles making requests and formatting the responses. """
import code +import contextlib import socket +import sys
import stem import stem.control @@ -19,6 +21,11 @@ import stem.util.tor_tools from stem.interpreter import STANDARD_OUTPUT, BOLD_OUTPUT, ERROR_OUTPUT, uses_settings, msg from stem.util.term import format
+try: + from cStringIO import StringIO +except ImportError: + from io import StringIO +
def _get_fingerprint(arg, controller): """ @@ -84,6 +91,17 @@ def _get_fingerprint(arg, controller): raise ValueError("'%s' isn't a fingerprint, nickname, or IP address" % arg)
+@contextlib.contextmanager +def redirect(stdout, stderr): + original = sys.stdout, sys.stderr + sys.stdout, sys.stderr = stdout, stderr + + try: + yield + finally: + sys.stdout, sys.stderr = original + + class ControlInterpreter(code.InteractiveConsole): """ Handles issuing requests and providing nicely formed responses, with support @@ -338,8 +356,13 @@ class ControlInterpreter(code.InteractiveConsole): is_tor_command = cmd in config.get('help.usage', {}) and cmd.lower() != 'events'
if self._run_python_commands and not is_tor_command: - self.is_multiline_context = code.InteractiveConsole.push(self, command) - return + console_output = StringIO() + + with redirect(console_output, console_output): + self.is_multiline_context = code.InteractiveConsole.push(self, command) + + output = console_output.getvalue() + return output if output else None else: try: output = format(self._controller.msg(command).raw_content().strip(), *STANDARD_OUTPUT)